Some checks failed
check / check (push) Has been cancelled
`make check` was green while the AddToken screen crashed on every open. `script/lint` is only `prettier --check`, so a used-but-not-imported identifier is invisible until a browser evaluates it. This adds a suite that runs the real popup in a real Chrome and treats any uncaught page error or console.error as a failure. - `script/test-e2e` (with `make test-e2e` as a thin shim) builds `dist/chrome/` and runs `tests/e2e/run.js` inside the Playwright image, pinned by digest. `playwright-core` is pinned to the matching 1.56.0 through `yarn.lock`; the two must be bumped together because the browsers ship inside the image. - Deliberately outside `script/test` and `script/check`: REPO_POLICIES caps `make test` at 20 seconds. Nothing under `tests/e2e/` is named `*.test.js`, so jest cannot pick it up either. - Launches with `channel: "chromium"`; the default headless shell silently refuses to load extensions with no error at all. The extension id is read from the service worker URL, never hardcoded. - All http(s) traffic is intercepted at the browser level and served from fixtures, so the run is deterministic and offline. Unrecognised outbound requests are reported as failures rather than allowed. - A missing build or an unavailable container fails loudly; a skip that looks like a pass is the failure mode this is meant to prevent. - One allowlisted page error, for the libsodium WASM CSP fallback tracked as #182, which is otherwise untouched here. The suite was demonstrated failing against the unfixed tree with `pageerror: showView is not defined` and `pageerror: addressDotHtml is not defined`, so it carries the two one-line import fixes it caught: closes #150 — `showView` restored to the destructure in `src/popup/views/addToken.js`, dropped bya22f33d, which made the AddToken screen unreachable and corrupted the navigation stack. closes #151 — `addressDotHtml` restored in `src/popup/views/transactionDetail.js`, dropped bydf031fd, which threw before `showView("transaction")` for every ERC-20 transfer. The shared `renderAddressHtml` helper is not used here on purpose: it hardcodes the `/address/` explorer URL, and this row needs the token-specific `/token/` link.
83 lines
3.1 KiB
JavaScript
83 lines
3.1 KiB
JavaScript
const { $, showView, showFlash, goBack } = require("./helpers");
|
|
const { getTopTokens } = require("../../shared/tokenList");
|
|
const { state, saveState } = require("../../shared/state");
|
|
const { lookupTokenInfo } = require("../../shared/balances");
|
|
const { isScamAddress } = require("../../shared/scamlist");
|
|
const { log } = require("../../shared/log");
|
|
|
|
function show() {
|
|
$("add-token-address").value = "";
|
|
$("add-token-info").textContent = "";
|
|
$("add-token-info").style.visibility = "hidden";
|
|
const list = $("common-token-list");
|
|
list.innerHTML = getTopTokens(25)
|
|
.map(
|
|
(t) =>
|
|
`<button class="common-token border border-border px-1 hover:bg-fg hover:text-bg cursor-pointer text-xs" data-address="${t.address}" data-symbol="${t.symbol}" data-decimals="${t.decimals}">${t.symbol}</button>`,
|
|
)
|
|
.join("");
|
|
list.querySelectorAll(".common-token").forEach((btn) => {
|
|
btn.addEventListener("click", () => {
|
|
$("add-token-address").value = btn.dataset.address;
|
|
});
|
|
});
|
|
showView("add-token");
|
|
}
|
|
|
|
function init(ctx) {
|
|
$("btn-add-token-confirm").addEventListener("click", async () => {
|
|
const contractAddr = $("add-token-address").value.trim();
|
|
if (!contractAddr || !contractAddr.startsWith("0x")) {
|
|
showFlash(
|
|
"Please enter a valid contract address starting with 0x.",
|
|
);
|
|
return;
|
|
}
|
|
const already = state.trackedTokens.find(
|
|
(t) => t.address.toLowerCase() === contractAddr.toLowerCase(),
|
|
);
|
|
if (already) {
|
|
showFlash(already.symbol + " is already being tracked.");
|
|
return;
|
|
}
|
|
if (isScamAddress(contractAddr)) {
|
|
showFlash("This address is on a known scam/fraud list.");
|
|
return;
|
|
}
|
|
const infoEl = $("add-token-info");
|
|
infoEl.textContent = "Looking up token...";
|
|
infoEl.style.visibility = "visible";
|
|
log.debugf("Looking up token contract", contractAddr);
|
|
try {
|
|
const info = await lookupTokenInfo(contractAddr, state.rpcUrl);
|
|
log.infof("Adding token", info.symbol, contractAddr);
|
|
state.trackedTokens.push({
|
|
address: contractAddr,
|
|
symbol: info.symbol,
|
|
decimals: info.decimals,
|
|
name: info.name,
|
|
});
|
|
await saveState();
|
|
ctx.doRefreshAndRender();
|
|
// Pop the stack (back to address detail) and re-render it
|
|
// so the newly added token is visible immediately.
|
|
if (state.viewStack.length > 0) {
|
|
state.viewStack.pop();
|
|
}
|
|
require("./addressDetail").show();
|
|
} catch (e) {
|
|
const detail = e.shortMessage || e.message || String(e);
|
|
log.errorf("Token lookup failed for", contractAddr, detail);
|
|
showFlash(detail);
|
|
infoEl.textContent = "";
|
|
infoEl.style.visibility = "hidden";
|
|
}
|
|
});
|
|
|
|
$("btn-add-token-back").addEventListener("click", () => {
|
|
goBack();
|
|
});
|
|
}
|
|
|
|
module.exports = { init, show };
|