1 Commits
Author SHA1 Message Date
sneak 20b07b6fe4 fix: Blockscout and Etherscan lookups are off until the user turns them on (closes #668)
check / check (push) Canceled after 0s
e2e / e2e-chrome (push) Canceled after 0s
e2e / e2e-firefox (push) Canceled after 0s
Out of the box the wallet sent the user's addresses to Blockscout for history
and token lookups. It sent each recipient to Etherscan for its label. Two
settings, "Use Blockscout" and "Check recipients on Etherscan", now gate those
requests where they are made. Both are off in a new install and offered
unticked on Welcome and in Settings. While one is off, the screens that relied
on it say so in a plain line naming the setting. After either changes in
Settings, Back draws again any screen a reopened popup can draw. ENS lookups
ask only the RPC endpoint, so a name resolved off-chain does not resolve.
README and the user guide say what is contacted by default and what each
setting adds.

Model: opus-5-5
2026-10-25 23:55:31 +00:00
17 changed files with 45 additions and 443 deletions

No files matched your search

+17 -35
View File
@@ -449,11 +449,6 @@ comes earlier and is not recorded. The tests take these steps in order:
- "Use Blockscout" is ticked from AddressDetail's gear. On "Back", AddressDetail
must ask Blockscout for its history and no longer say the setting is off.
Blockscout must then be asked for the token balances.
- The stub Blockscout then reports a token the user has not tracked. Home lists
it. "Use Blockscout" is unticked from AddressDetail's gear. On "Back", the
token must be gone from AddressDetail, from Send's token dropdown and from
Home. Those three screens must each show the line saying the setting is off.
The setting is then ticked again.
- "Check recipients on Etherscan" is ticked from ConfirmTx's gear. On "Back",
ConfirmTx must ask Etherscan about the recipient and show the label the stub
page gives it.
@@ -1434,13 +1429,11 @@ figures while Blockscout fails.
The refresh asks Blockscout only while the user has "Use Blockscout" on. The
setting is off until the user turns it on. While it is off:
- Only tracked tokens are listed. Turning the setting off in Settings drops
every other token from every address at once.
- Only tracked tokens are listed. Untracked tokens from earlier refreshes are
dropped.
- A tracked token's entry has no holder count and no `decimals` from Blockscout.
- A tracked token's balance uses the decimals from the bundled list, or else the
decimals saved when the token was tracked.
A refresh that started before the setting changed saves nothing when it returns.
- A tracked token's balance is stated at the scale the bundled list or the
tracked token records.
A tracked token is shown when its balance is nonzero, and any other ERC-20 when
its balance is nonzero and it is in the bundled known-token list or has 1,000 or
@@ -1630,14 +1623,10 @@ renders as it goes, and `viewRouter.js` records every screen that reaches
more — rendering it a second time would re-fetch and overwrite what it holds,
such as an edit typed into Settings and not yet saved. Home is the one screen
"Back" always re-renders, so the wallet list reflects anything that changed
while the user was away from it.
Changing "Use Blockscout" or "Check recipients on Etherscan" in Settings makes
every screen but Settings count as not yet rendered. "Back" then renders again
any screen a reopened popup can render. A change to "Use Blockscout" also cuts
the stack, as a network switch does (below). The cut drops Send, whose token
dropdown was filled under the old setting. "Back" cannot render Send again. A
change to "Check recipients on Etherscan" leaves the stack as it is.
while the user was away from it. Changing "Use Blockscout" or "Check recipients
on Etherscan" in Settings makes every screen but Settings count as not yet
rendered. "Back" then renders again any screen a reopened popup can render. Any
other screen, such as Send, is unhidden as it was. The stack is left as it is.
A network switch leaves every screen on the page showing the previous network.
The user makes it in Settings, or approves a site's request and the background
@@ -1888,9 +1877,6 @@ view would leave a wallet one click from deletion.
- From: address with color dot + etherscan link
- What to send: token dropdown (or static display with contract address when
locked from AddressToken)
- While "Use Blockscout" is off, a line under the token dropdown: "Only
tracked tokens are listed, because "Use Blockscout" is off in Settings."
The line is hidden with the dropdown when Send is opened from AddressToken
- To: address or ENS name input, with an inline validation message
- Amount input with current balance display, which reads
`Current balance: unknown (SYMBOL)` for a token whose scale is unknown, as
@@ -2131,11 +2117,12 @@ view would leave a wallet one click from deletion.
AddressToken. The screen describes the transaction on the network it was sent
on, whichever network is active: its block, network details, decoded details
and raw data are read from that network's Blockscout, the one Settings has for
it, and its etherscan links open that network's explorer. The block, network
details, decoded details and raw data are read only while "Use Blockscout" is
on. While it is off, a line in their place says "No block, decoded details,
network details or raw data are shown, because "Use Blockscout" is off in
Settings."
it, and its etherscan links open that network's explorer. They are read only
while "Use Blockscout" is on. The user can open Settings from this screen,
turn the setting off and press Back. The screen is then drawn again without
asking Blockscout. A line in place of those details says "No block, decoded
details, network details or raw data are shown, because "Use Blockscout" is
off in Settings."
- **Elements** (grouped into logical blocks using light well containers; field
labels are self-explanatory so groups have no headings):
- "Transaction" heading, "Back" button
@@ -2258,8 +2245,7 @@ view would leave a wallet one click from deletion.
- **Transitions**:
- Ticking or unticking "Use Blockscout" or "Check recipients on Etherscan" →
stores the setting (no screen change). The next balance refresh and every
screen drawn after that follow it. Unticking "Use Blockscout" also drops
every token the user has not tracked from every address
screen drawn after that follow it
- "+ Add wallet" → **AddWallet**
- "+ Add token" → **SettingsAddToken**
- `[recovery phrase]` on an HD wallet → **ShowRecoveryPhrase**
@@ -2278,8 +2264,7 @@ view would leave a wallet one click from deletion.
nothing and tells the background nothing
- Ten clicks on the version → reveals the Debug well (no screen change)
- "Back" (or Settings gear again) → previous screen (Home); after a network
switch or a change to "Use Blockscout", the stack is cut first (see the
top of Screen Map)
switch, the stack is cut first (see the top of Screen Map)
#### ShowRecoveryPhrase (`show-phrase`)
@@ -2436,8 +2421,6 @@ view would leave a wallet one click from deletion.
money. The predicate is `addressHoldsFunds()` in
`src/popup/views/helpers.js`, unrounded and token-aware. A balance is a
warning, never a refusal.
- While "Use Blockscout" is off, a line under the warning: "Only tracked
tokens are listed, because "Use Blockscout" is off in Settings."
- The rule that a wallet always keeps at least one address, and that
removing the last one means deleting the wallet from Settings
- Error line
@@ -2822,8 +2805,7 @@ Sent the user's data only while the user has turned the setting on:
- **Used for**:
- transaction history (normal transactions and ERC-20 token transfers),
for Home, AddressDetail and AddressToken
- the balances of the ERC-20 tokens the user has not tracked, for Home,
AddressDetail, Send and DeleteAddress
- the balances of the ERC-20 tokens the user has not tracked
- token holder counts, for spam filtering
- a transaction's block, network details and calldata, for
TransactionDetail
+1 -2
View File
@@ -112,8 +112,7 @@ Blockscout is an open-source blockchain explorer. AutistMask uses it only while
You can change this in Settings to a self-hosted Blockscout instance. While the
setting is off, each screen that would show Blockscout's data says so instead.
Only the tokens you track are listed. When you turn the setting off, every other
token leaves the lists at once.
Only the tokens you track are listed.
When it is contacted, while "Use Blockscout" is on:
-5
View File
@@ -1386,10 +1386,6 @@ const RECENT_BALANCE_REFRESH_MS = Math.floor(BALANCE_REFRESH_PERIOD_MS / 2);
// back over them (https://git.eeqj.de/sneak/AutistMask/issues/577).
// lastBalanceRefresh is left as the switch set it, so the next tick refreshes
// the new network.
//
// Nothing is applied either when "Use Blockscout" stored NOW is not the one the
// refresh ran with. Turning it off dropped the tokens the user has not tracked
// (src/popup/views/settings.js), and this refresh must not bring them back.
async function backgroundRefresh() {
const s = await getState();
const now = Date.now();
@@ -1415,7 +1411,6 @@ async function backgroundRefresh() {
await updateState((fresh) => {
if (fresh.networkId !== s.networkId) return;
if (fresh.useBlockscout !== s.useBlockscout) return;
for (const wallet of fresh.wallets) {
for (const addr of wallet.addresses || []) {
const got = refreshed.get(String(addr.address).toLowerCase());
+6 -24
View File
@@ -569,23 +569,12 @@
</div>
<div class="mb-2">
<label class="block mb-1">What to send</label>
<!-- The token dropdown and the line under it. Both are
hidden when AddressToken opens Send for its own token. -->
<div id="send-token-dropdown">
<select
id="send-token"
class="border border-border p-1 w-full font-mono text-sm bg-bg text-fg"
>
<option value="ETH">ETH</option>
</select>
<p
id="send-tokens-note"
class="text-xs text-muted hidden"
>
Only tracked tokens are listed, because "Use
Blockscout" is off in Settings.
</p>
</div>
<select
id="send-token"
class="border border-border p-1 w-full font-mono text-sm bg-bg text-fg"
>
<option value="ETH">ETH</option>
</select>
<div id="send-token-static" class="text-sm hidden"></div>
</div>
<div class="mb-2">
@@ -1380,13 +1369,6 @@
>
&nbsp;
</div>
<p
id="delete-address-tokens-note"
class="text-xs text-muted mb-2 hidden"
>
Only tracked tokens are listed, because "Use Blockscout" is
off in Settings.
</p>
<p class="text-xs text-muted mb-3">
A wallet always keeps at least one address. To remove the
last one, delete the whole wallet from Settings instead.
+4 -9
View File
@@ -79,17 +79,14 @@ let refreshTimer = null;
// A switch while the refresh ran cleared every address's balances
// (applyChainSwitchFields() in src/shared/chainSwitchFields.js), and the
// previous network's must not come back over them
// (https://git.eeqj.de/sneak/AutistMask/issues/577). The same holds when "Use
// Blockscout" changed while the refresh ran. Turning it off dropped the tokens
// the user has not tracked (views/settings.js), and this refresh must not bring
// them back. A dropped refresh is not recorded as done. Results are copied by
// address, so an address added or removed meanwhile is left as it is.
// (https://git.eeqj.de/sneak/AutistMask/issues/577). A dropped refresh is not
// recorded as done. Results are copied by address, so an address added or
// removed meanwhile is left as it is.
async function doRefreshAndRender() {
if (refreshInFlight) return;
refreshInFlight = true;
try {
const networkId = state.networkId;
const useBlockscout = state.useBlockscout;
const wallets = structuredClone(state.wallets);
await Promise.all([
refreshPrices(),
@@ -97,7 +94,7 @@ async function doRefreshAndRender() {
wallets,
state.rpcUrl,
state.blockscoutUrl,
useBlockscout,
state.useBlockscout,
state.trackedTokens,
networkId,
pageClosed.signal,
@@ -112,8 +109,6 @@ async function doRefreshAndRender() {
await saveState((stored) => {
if (state.networkId !== networkId) return false;
if (stored.networkId !== networkId) return false;
if (state.useBlockscout !== useBlockscout) return false;
if (stored.useBlockscout !== useBlockscout) return false;
for (const wallet of state.wallets) {
for (const addr of wallet.addresses) {
const got = refreshed.get(addr.address);
+1 -1
View File
@@ -237,7 +237,7 @@ function init(_ctx) {
}
$("send-to").value = "";
$("send-amount").value = "";
$("send-token-dropdown").classList.remove("hidden");
$("send-token").classList.remove("hidden");
$("send-token-static").classList.add("hidden");
updateSendBalance();
resetSendValidation();
+1 -1
View File
@@ -330,7 +330,7 @@ function init(_ctx) {
$("send-token").value = tokenId;
}
// Hide dropdown, show static token display
$("send-token-dropdown").classList.add("hidden");
$("send-token").classList.add("hidden");
let staticHtml = `<div class="font-bold">${escapeHtml(displaySymbol(currentSymbol))}</div>`;
if (tokenId !== "ETH") {
staticHtml += `<div class="text-xs">${renderAddressHtml(tokenId)}</div>`;
-5
View File
@@ -119,11 +119,6 @@ function show(walletIdx, addrIdx) {
$("delete-address-recovery").textContent = recoveryPathText(wallet);
$("delete-address-balance").innerHTML = balanceWarningHtml(addr);
// Tokens the user has not tracked are Blockscout's to report.
$("delete-address-tokens-note").classList.toggle(
"hidden",
!!state.useBlockscout,
);
setFlash("");
showView("delete-address-confirm");
+1 -1
View File
@@ -455,7 +455,7 @@ function init(ctx) {
}
$("send-to").value = "";
$("send-amount").value = "";
$("send-token-dropdown").classList.remove("hidden");
$("send-token").classList.remove("hidden");
$("send-token-static").classList.add("hidden");
renderSendTokenSelect(addr);
updateSendBalance();
+1 -3
View File
@@ -141,8 +141,6 @@ function updateToValidation() {
}
function renderSendTokenSelect(addr) {
// Tokens the user has not tracked are Blockscout's to report.
$("send-tokens-note").classList.toggle("hidden", !!state.useBlockscout);
const sel = $("send-token");
sel.innerHTML = `<option value="ETH">${escapeHtml(nativeCurrency())}</option>`;
const fraudSet = new Set(
@@ -428,7 +426,7 @@ function init(_ctx) {
});
$("btn-send-back").addEventListener("click", () => {
$("send-token-dropdown").classList.remove("hidden");
$("send-token").classList.remove("hidden");
$("send-token-static").classList.add("hidden");
goBack();
});
-22
View File
@@ -261,7 +261,6 @@ async function renderSiteLists() {
// native token: any other token there was picked on the previous network, so
// it is no longer selected either. Without a wallet the stack starts at
// Welcome, which that cut would drop, and Welcome shows nothing from a network.
// A change to "Use Blockscout" cuts the stack the same way (init() below).
function cutViewStack() {
if (!state.hasWallet) return;
if (state.selectedToken !== "ETH") {
@@ -373,30 +372,9 @@ function init(_ctx) {
// switch does. Back then draws again any screen a reopened popup can draw.
// Welcome offers the same two settings, and Back only unhides it, so its
// boxes are set here too.
//
// A change to "Use Blockscout" also cuts the stack, as a network switch
// does (cutViewStack() above). Send's token dropdown was filled under the
// old setting, and Back cannot draw Send again.
//
// Turning "Use Blockscout" off drops the tokens the user has not tracked
// from every address. Only Blockscout reports them, so no screen lists them
// from then on.
$("settings-use-blockscout").addEventListener("change", async () => {
state.useBlockscout = $("settings-use-blockscout").checked;
$("welcome-use-blockscout").checked = state.useBlockscout;
if (!state.useBlockscout) {
const tracked = new Set(
state.trackedTokens.map((t) => t.address.toLowerCase()),
);
for (const wallet of state.wallets) {
for (const addr of wallet.addresses) {
addr.tokenBalances = (addr.tokenBalances || []).filter(
(row) => tracked.has(String(row.address).toLowerCase()),
);
}
}
}
cutViewStack();
resetRenderedViews();
markViewRendered("settings");
await saveState();
-57
View File
@@ -450,60 +450,3 @@ describe("a balance refresh under a network switch", () => {
);
});
});
describe("a balance refresh under a change of Use Blockscout", () => {
// Turning "Use Blockscout" off drops the tokens the user has not tracked
// (src/popup/views/settings.js). A refresh that started while it was on
// must not write them back when it returns. The same refresh in the popup
// is in tests/blockscoutEtherscanSettings.test.js.
test("a refresh that returns after Use Blockscout was turned off writes nothing", async () => {
const roundTrip = deferred();
const started = deferred();
const handed = [];
const bg = loadWorker("mainnet", {
refreshBalances: async (
wallets,
rpcUrl,
explorer,
useBlockscout,
) => {
handed.push(useBlockscout);
started.resolve();
await roundTrip.promise;
wallets[0].addresses[0].tokenBalances = [
{
address: "0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
name: "Test Token",
symbol: "TST",
decimals: 18,
balance: "5.0",
holders: 50000,
},
];
},
});
global.chrome.storage.write("autistmask", {
...bg.persisted(),
useBlockscout: true,
});
const refresh = bg.fireBalanceAlarm();
await started.promise;
// The user unticks "Use Blockscout" in Settings while the round trip
// is out.
global.chrome.storage.write("autistmask", {
...bg.persisted(),
useBlockscout: false,
});
roundTrip.resolve();
await refresh;
expect(handed).toEqual([true]);
const after = bg.persisted();
expect(after.wallets[0].addresses[0].tokenBalances).toEqual([]);
expect(after.lastBalanceRefresh).toBe(0);
});
});
+7 -200
View File
@@ -7,10 +7,6 @@
// Blockscout URL in Settings. It asks that URL only for `/stats` and carries no
// user data. It is made whether or not the setting is on.
//
// Only Blockscout reports the tokens the user has not tracked. Turning "Use
// Blockscout" off in Settings drops them from every address, so no screen lists
// them from then on.
//
// The functions that make the requests are driven directly, against a fetch()
// that records every URL it is asked for. The screens are driven through the
// real popup over a stored profile (tests/support/popupBoot.js), whose fetch()
@@ -24,7 +20,6 @@ const {
cleanupPopup,
unversionedValidProfile,
ADDRESS,
TOKEN_ADDRESS,
} = require("./support/popupBoot");
const { makeStorageStub } = require("./support/storageStub");
const {
@@ -371,10 +366,10 @@ describe("the popup", () => {
expect(on.hidden("confirm-etherscan-warning")).toBe(false);
});
// Ticks or unticks a checkbox on the page, as the user does.
async function setBox(page, id, checked) {
// Ticks a checkbox on the page, as the user does.
async function tick(page, id) {
const box = page.node(id);
box.checked = checked;
box.checked = true;
for (const fn of box.listeners.change) await fn();
await page.settle();
}
@@ -387,9 +382,9 @@ describe("the popup", () => {
false,
);
await setBox(page, "welcome-use-blockscout", true);
await tick(page, "welcome-use-blockscout");
expect(page.storage.read("autistmask").useBlockscout).toBe(true);
await setBox(page, "welcome-check-recipients-on-etherscan", true);
await tick(page, "welcome-check-recipients-on-etherscan");
expect(page.storage.read("autistmask").checkRecipientsOnEtherscan).toBe(
true,
);
@@ -403,201 +398,13 @@ describe("the popup", () => {
page.node("settings-check-recipients-on-etherscan").checked,
).toBe(false);
await setBox(page, "settings-use-blockscout", true);
await tick(page, "settings-use-blockscout");
expect(page.storage.read("autistmask").useBlockscout).toBe(true);
await setBox(page, "settings-check-recipients-on-etherscan", true);
await tick(page, "settings-check-recipients-on-etherscan");
expect(page.storage.read("autistmask").checkRecipientsOnEtherscan).toBe(
true,
);
});
// A token the user tracks, and one Blockscout reported that the user has
// not tracked. Both are written in lower case, as the balance rows' and
// the dropdown's token ids are compared below.
const TRACKED = "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
const UNTRACKED = TOKEN_ADDRESS.toLowerCase();
const SECOND_ADDRESS = "0x3333333333333333333333333333333333333333";
function tokenRow(address, symbol) {
return {
address,
name: symbol,
symbol,
decimals: 18,
balance: "5.0",
holders: 50000,
};
}
// AddressDetail of the first of two addresses, as a reopened popup draws
// it. Both addresses hold the tracked token. While "Use Blockscout" is on,
// both hold the untracked one too.
function onAddressDetail(useBlockscout) {
const profile = unversionedValidProfile({
useBlockscout,
currentView: "address",
viewStack: ["main"],
selectedWallet: 0,
selectedAddress: 0,
trackedTokens: [
{ address: TRACKED, name: "TRK", symbol: "TRK", decimals: 18 },
],
});
const wallet = profile.wallets[0];
wallet.nextIndex = 2;
wallet.addresses.push({ address: SECOND_ADDRESS, balance: "0.0" });
for (const addr of wallet.addresses) {
addr.tokenBalances = useBlockscout
? [tokenRow(TRACKED, "TRK"), tokenRow(UNTRACKED, "TST")]
: [tokenRow(TRACKED, "TRK")];
}
return profile;
}
// The token ids of the options the page has created since it had created
// `from` elements. The page stub keeps no children, so the options Send's
// dropdown was filled with are read from there.
function optionsSince(page, from) {
return page.document.created
.slice(from)
.filter((el) => el.tagName === "OPTION")
.map((el) => el.value.toLowerCase());
}
test("unticking Use Blockscout from AddressDetail's gear takes the untracked token off AddressDetail, Send's dropdown and Home on Back", async () => {
const page = await bootPopup(onAddressDetail(true));
expect(page.visibleViews()).toEqual(["address"]);
expect(page.node("address-balances").innerHTML).toContain(UNTRACKED);
await page.click("btn-settings");
await setBox(page, "settings-use-blockscout", false);
const from = page.document.created.length;
await page.click("btn-settings-back");
expect(page.visibleViews()).toEqual(["address"]);
const balances = page.node("address-balances").innerHTML;
expect(balances).toContain(TRACKED);
expect(balances).not.toContain(UNTRACKED);
expect(page.hidden("address-tokens-note")).toBe(false);
expect(optionsSince(page, from)).toEqual([TRACKED]);
await page.click("btn-send");
expect(page.visibleViews()).toEqual(["send"]);
expect(page.hidden("send-token-dropdown")).toBe(false);
expect(page.hidden("send-tokens-note")).toBe(false);
await page.click("btn-send-back");
await page.click("btn-address-back");
expect(page.visibleViews()).toEqual(["main"]);
const home = page.node("wallet-list").innerHTML;
expect(home).toContain(TRACKED);
expect(home).not.toContain(UNTRACKED);
const stored = page.storage.read("autistmask");
for (const addr of stored.wallets[0].addresses) {
expect(
addr.tokenBalances.map((row) => row.address.toLowerCase()),
).toEqual([TRACKED]);
}
});
// Send's dropdown was filled under the old setting, and Back cannot draw
// Send again. So Back lands on the screen under it.
test.each([
["unticking", true],
["ticking", false],
])(
"%s Use Blockscout from Send's gear lands Back on AddressDetail",
async (_how, before) => {
const page = await bootPopup(onAddressDetail(before));
await page.click("btn-send");
expect(page.visibleViews()).toEqual(["send"]);
await page.click("btn-settings");
await setBox(page, "settings-use-blockscout", !before);
await page.click("btn-settings-back");
expect(page.visibleViews()).toEqual(["address"]);
expect(page.hidden("address-tokens-note")).toBe(!before);
},
);
test("Send says under its token dropdown that only tracked tokens are listed while Use Blockscout is off", async () => {
const off = await bootPopup(onAddressDetail(false));
await off.click("btn-send");
expect(off.hidden("send-token-dropdown")).toBe(false);
expect(off.hidden("send-tokens-note")).toBe(false);
cleanupPopup();
const on = await bootPopup(onAddressDetail(true));
await on.click("btn-send");
expect(on.hidden("send-token-dropdown")).toBe(false);
expect(on.hidden("send-tokens-note")).toBe(true);
});
test("Send opened from AddressToken shows neither the dropdown nor its line", async () => {
const page = await bootPopup({
...onAddressDetail(false),
currentView: "address-token",
viewStack: ["main", "address"],
selectedToken: "ETH",
});
expect(page.visibleViews()).toEqual(["address-token"]);
await page.click("btn-address-token-send");
expect(page.visibleViews()).toEqual(["send"]);
expect(page.hidden("send-token-dropdown")).toBe(true);
expect(page.hidden("send-token-static")).toBe(false);
});
test("DeleteAddress says only tracked tokens are listed while Use Blockscout is off", async () => {
for (const useBlockscout of [false, true]) {
const page = await bootPopup(onAddressDetail(useBlockscout));
require("../src/popup/views/deleteAddress").show(0, 1);
expect(page.visibleViews()).toEqual(["delete-address-confirm"]);
expect(page.hidden("delete-address-tokens-note")).toBe(
useBlockscout,
);
cleanupPopup();
}
});
// Turning the setting off dropped the untracked token. A refresh that
// started while it was on must not bring the token back when it returns.
// The same refresh in the background is in
// tests/backgroundStateIsolation.test.js.
test("a refresh that returns after Use Blockscout was turned off saves none of its tokens", async () => {
const page = await bootPopup(onAddressDetail(true));
const { refreshBalances: held } = require("../src/shared/balances");
let answer;
held.mockImplementationOnce(async (wallets) => {
await new Promise((resolve) => {
answer = resolve;
});
wallets[0].addresses[0].tokenBalances = [
tokenRow(TRACKED, "TRK"),
tokenRow(UNTRACKED, "TST"),
];
});
const ticking = page.tick();
await page.settle();
await page.click("btn-settings");
await setBox(page, "settings-use-blockscout", false);
const before = page.storage.read("autistmask").lastBalanceRefresh;
answer();
await ticking;
const stored = page.storage.read("autistmask");
expect(
stored.wallets[0].addresses[0].tokenBalances.map((row) =>
row.address.toLowerCase(),
),
).toEqual([TRACKED]);
expect(stored.lastBalanceRefresh).toBe(before);
await page.click("btn-settings-back");
expect(page.node("address-balances").innerHTML).not.toContain(
UNTRACKED,
);
});
});
describe("the background", () => {
+3 -63
View File
@@ -284,10 +284,9 @@ test("the exact confirmation phrase erases the record and reloads into Welcome (
//
// Before either setting is changed, these tests drive Home, AddressDetail,
// AddressToken and ConfirmTx, and the background's own balance refresh. Then
// they turn each setting on and watch its requests start. "Use Blockscout" is
// also turned off once and on again, to see a token the user has not tracked
// leave every list. TransactionDetail, which also asks Blockscout, is left to
// the unit tests in tests/blockscoutEtherscanSettings.test.js.
// they turn each setting on and watch its requests start. TransactionDetail,
// which also asks Blockscout, is left to the unit tests in
// tests/blockscoutEtherscanSettings.test.js.
// What the three transaction lists say while Use Blockscout is off. Written
// out here rather than imported, so the assertion does not compare the popup
@@ -503,65 +502,6 @@ test("turning on Use Blockscout from AddressDetail's gear asks Blockscout for th
);
});
// Unticked from AddressDetail's gear while the address holds the stub token,
// which the user has not tracked and only Blockscout reports. Ticked again at
// the end, so the rest of the run has Blockscout as before.
test("turning off Use Blockscout from AddressDetail's gear takes an untracked token off AddressDetail, Send and Home on Back (#668)", async (env) => {
env.routeOpts.ethBalanceWei = toHexWei(FUNDED_ETH_WEI);
env.routeOpts.seedTokenBalance = true;
const tokenRow = '[data-token="' + STUB_TOKEN.address + '"]';
try {
await settleOnMain(env, { ethWei: FUNDED_ETH_WEI, expectToken: true });
await openAddressDetail(env.page);
await visible(env.page, "#address-balances " + tokenRow);
await openSettings(env.page);
await env.page.uncheck("#settings-use-blockscout");
await waitForPersisted(
env.page,
"useBlockscout",
false,
"once unticked",
);
await env.page.click("#btn-settings-back");
await visible(env.page, "#view-address");
await visible(env.page, "#address-tokens-note");
assert(
(await env.page
.locator("#address-balances " + tokenRow)
.count()) === 0,
"AddressDetail still lists the untracked token",
);
await env.page.click("#btn-send");
await visible(env.page, "#view-send");
await visible(env.page, "#send-tokens-note");
const offered = await env.page.$$eval("#send-token option", (opts) =>
opts.map((opt) => opt.value.toLowerCase()),
);
assert(
!offered.includes(STUB_TOKEN.address),
"Send's dropdown still offers the untracked token",
);
await env.page.click("#btn-send-back");
await visible(env.page, "#view-address");
await goHome(env.page);
await visible(env.page, "#home-tokens-note");
assert(
(await env.page.locator("#wallet-list " + tokenRow).count()) === 0,
"Home still lists the untracked token",
);
} finally {
await openSettings(env.page);
await env.page.check("#settings-use-blockscout");
await waitForPersisted(env.page, "useBlockscout", true, "ticked again");
await env.page.click("#btn-settings-back");
env.routeOpts.ethBalanceWei = null;
env.routeOpts.seedTokenBalance = false;
}
});
// Ticked from ConfirmTx's gear, so Back lands on the screen that said no
// Etherscan check was made. Left on for the rest of the run, so the later
// confirmation screens are driven with the check made.
+1 -5
View File
@@ -286,12 +286,8 @@ describe("a malformed fraudContracts", () => {
function stubSendDocument() {
const select = { innerHTML: "", children: [] };
select.appendChild = (child) => select.children.push(child);
const elements = {
"send-token": select,
"send-tokens-note": { classList: { toggle: () => {} } },
};
globalThis.document = {
getElementById: (id) => elements[id] || null,
getElementById: (id) => (id === "send-token" ? select : null),
createElement: () => ({ value: "", textContent: "" }),
};
return select;
+1 -5
View File
@@ -27,12 +27,8 @@ let select;
function installStubDocument() {
select = { innerHTML: "", children: [] };
select.appendChild = (child) => select.children.push(child);
const elements = {
"send-token": select,
"send-tokens-note": { classList: { toggle: () => {} } },
};
globalThis.document = {
getElementById: (id) => elements[id] || null,
getElementById: (id) => (id === "send-token" ? select : null),
createElement: () => ({ value: "", textContent: "" }),
};
}
+1 -5
View File
@@ -485,12 +485,8 @@ describe("surface 2: the Send token selector", () => {
function render(tokenBalances) {
select = { innerHTML: "", children: [] };
select.appendChild = (child) => select.children.push(child);
const elements = {
"send-token": select,
"send-tokens-note": { classList: { toggle: () => {} } },
};
globalThis.document = {
getElementById: (id) => elements[id] || null,
getElementById: (id) => (id === "send-token" ? select : null),
createElement: () => ({ value: "", textContent: "" }),
};
renderSendTokenSelect({