Files
AutistMask/tests/sendTokenSelect.test.js
T
sneak 95b579d7f0
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run
fix: Blockscout and Etherscan lookups are off until the user turns them on (closes #668)
Out of the box the wallet sent the user's addresses to Blockscout. It sent each
recipient to Etherscan for its label. Two settings, "Use Blockscout" and "Check
recipients on Etherscan", now gate those requests. 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. Each gated request reads its setting
from storage before it asks and when the answer lands. An answer that lands
after the setting went off is dropped. An open popup takes a change another page
saved and draws its screens again. While "Use Blockscout" is off, no address
keeps an untracked token. ENS lookups ask only the RPC endpoint.

Model: opus-5-5
2026-10-26 07:49:39 +00:00

128 lines
4.4 KiB
JavaScript

// Tests for the token filtering in the Send view's token selector
// (src/popup/views/send.js).
//
// The selector decides which of the user's tokens can be spent at all, so
// over-filtering here is worse than in the history list: the asset is not
// merely hidden, it becomes unspendable through the UI. Issue #230: an
// explorer that omits holders_count was read as "zero holders" and the token
// disappeared from this list.
//
// renderSendTokenSelect only ever touches getElementById, createElement,
// innerHTML, value, textContent and appendChild, so a small stub document is
// enough to drive it; the real DOM behaviour of the view is covered by
// tests/e2e/run.js.
globalThis.chrome = {
storage: { local: { get: async () => ({}), set: async () => {} } },
};
const { state } = require("../src/shared/state");
const { renderSendTokenSelect } = require("../src/popup/views/send");
const USDC_CONTRACT = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
const NOVEL_TOKEN = "0x1111111111111111111111111111111111111111";
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,
createElement: () => ({ value: "", textContent: "" }),
};
}
// The symbols offered for sending, excluding the hardcoded ETH option that
// renderSendTokenSelect writes straight into innerHTML.
function offeredTokens() {
return select.children.map((opt) => opt.value.toLowerCase());
}
function tokenBalance(overrides) {
return {
address: NOVEL_TOKEN,
symbol: "SPAMTKN",
decimals: 18,
balance: "12.5",
holders: 50000,
...overrides,
};
}
function render(tokenBalances) {
installStubDocument();
renderSendTokenSelect({ address: "0x" + "a".repeat(40), tokenBalances });
}
beforeEach(() => {
state.fraudContracts = [];
state.hideLowHolderTokens = true;
});
describe("the low-holder rule in the send token selector", () => {
test("ETH is always offered", () => {
render([]);
expect(select.innerHTML).toBe('<option value="ETH">ETH</option>');
expect(offeredTokens()).toEqual([]);
});
test("a token with plenty of holders is offered", () => {
render([tokenBalance()]);
expect(offeredTokens()).toEqual([NOVEL_TOKEN]);
});
test("a token reporting zero holders is withheld", () => {
render([tokenBalance({ holders: 0 })]);
expect(offeredTokens()).toEqual([]);
});
test("boundary: 999 holders is withheld, 1000 is offered", () => {
render([tokenBalance({ holders: 999 })]);
expect(offeredTokens()).toEqual([]);
render([tokenBalance({ holders: 1000 })]);
expect(offeredTokens()).toEqual([NOVEL_TOKEN]);
});
// Issue #230: an unknown holder count must not read as zero. A token the
// user demonstrably holds — it has a balance — cannot be made unspendable
// by a field the block explorer failed to report.
test("a token whose holder count is unknown is still offered", () => {
render([tokenBalance({ holders: null })]);
expect(offeredTokens()).toEqual([NOVEL_TOKEN]);
});
test("a token balance carrying no holders field at all is offered", () => {
const t = tokenBalance();
delete t.holders;
render([t]);
expect(offeredTokens()).toEqual([NOVEL_TOKEN]);
});
test("the rule is bypassed entirely when the setting is off", () => {
state.hideLowHolderTokens = false;
render([tokenBalance({ holders: 0 })]);
expect(offeredTokens()).toEqual([NOVEL_TOKEN]);
});
});
describe("the other send-selector rules are unaffected", () => {
test("a token spoofing a known symbol from a wrong address is withheld", () => {
render([
tokenBalance({ symbol: "USDC", holders: null }),
tokenBalance({ address: USDC_CONTRACT, symbol: "USDC" }),
]);
expect(offeredTokens()).toEqual([USDC_CONTRACT.toLowerCase()]);
});
test("a blocklisted fraud contract is withheld even with an unknown count", () => {
state.fraudContracts = [NOVEL_TOKEN.toUpperCase()];
render([tokenBalance({ holders: null })]);
expect(offeredTokens()).toEqual([]);
});
});