1 Commits
Author SHA1 Message Date
clawbot 5f332f4074 fix: a popup reload no longer logs the requests it cancels, except on the transaction detail and confirmation screens (closes #475)
check / check (push) Successful in 5m59s
e2e / e2e-chrome (push) Successful in 5m29s
e2e / e2e-firefox (push) Successful in 2m42s
The transaction lists and ENS name lookups on the address and token
screens, the address scan after a wallet is created, the endpoint checks
in Settings, the wait screen's receipt check, the Send screen's Max fee
estimate and the token lookup on both add-token screens now check the
signal the popup aborts on pagehide before reporting a failed request.
scanForAddresses(), resolveEnsNames() and lookupTokenInfo() take the
signal.

End-to-end tests reload the popup on the address screen and during the
address scan with their requests held. Jest tests show each of these
reports a real failure and stays silent once the popup has closed. The
transaction detail and confirmation screens are left out: they discard
the popup context that carries the signal.

Model: opus-5-5
2026-10-06 17:17:24 +00:00
5 changed files with 15 additions and 51 deletions
-9
View File
@@ -61,15 +61,6 @@ but the review is broader than any of them.
confirmation screen (its fee estimate and its recipient checks), because they confirmation screen (its fee estimate and its recipient checks), because they
discard the popup context that carries the signal. discard the popup context that carries the signal.
- 2026-10-06: The private key export screen opens again in the same popup
session ([#460](https://git.eeqj.de/sneak/AutistMask/issues/460)). `show()`
found the address line through the element inside it, which its own rendering
replaced, so the second open threw before it navigated. The line now carries
the `export-privkey-address` id itself. `tests/exportPrivkey.test.js` opens
the screen twice, its DOM stub now takes an element out of the document when
its parent's contents are replaced, and the `#253` e2e case no longer reopens
the popup before its second open.
- 2026-10-06: The canonical files are re-vendored from `sneak/prompts` at - 2026-10-06: The canonical files are re-vendored from `sneak/prompts` at
`dd4027b` ([#472](https://git.eeqj.de/sneak/AutistMask/issues/472)). The `dd4027b` ([#472](https://git.eeqj.de/sneak/AutistMask/issues/472)). The
`Dockerfile` has separate `lint` and `test` phases, and its last stage depends `Dockerfile` has separate `lint` and `test` phases, and its last stage depends
+8 -1
View File
@@ -391,7 +391,14 @@
></div> ></div>
<h2 class="font-bold mb-1">Export Private Key</h2> <h2 class="font-bold mb-1">Export Private Key</h2>
<p class="text-xs mb-1" id="export-privkey-title"></p> <p class="text-xs mb-1" id="export-privkey-title"></p>
<div id="export-privkey-address" class="text-xs mb-3"></div> <div class="text-xs mb-3">
<span id="export-privkey-dot"></span>
<span
id="export-privkey-address"
class="cursor-pointer"
title="Click to copy"
></span>
</div>
<p class="text-xs mb-3 text-muted"> <p class="text-xs mb-3 text-muted">
Warning: anyone with this private key can access and Warning: anyone with this private key can access and
transfer all funds from this address. Never share it. transfer all funds from this address. Never share it.
+1 -1
View File
@@ -98,7 +98,7 @@ function show(walletIdx, addrIdx) {
$("export-privkey-title").textContent = $("export-privkey-title").textContent =
wallet.name + " — Address " + (addrIdx + 1); wallet.name + " — Address " + (addrIdx + 1);
const addrContainer = $("export-privkey-address"); const addrContainer = $("export-privkey-dot").parentElement;
addrContainer.innerHTML = renderAddressHtml(addr.address); addrContainer.innerHTML = renderAddressHtml(addr.address);
attachCopyHandlers(addrContainer); attachCopyHandlers(addrContainer);
+4 -2
View File
@@ -1142,8 +1142,10 @@ test("leaving by the settings gear wipes the private key (#253)", async (env) =>
test("leaving while the decrypt is in flight reveals no private key (#253)", async (env) => { test("leaving while the decrypt is in flight reveals no private key (#253)", async (env) => {
try { try {
await leavePrivkeyScreen(env.page); await leavePrivkeyScreen(env.page);
// The second open in this popup session // The export screen cannot yet be opened twice in one popup session
// (https://git.eeqj.de/sneak/AutistMask/issues/460). // (https://git.eeqj.de/sneak/AutistMask/issues/460), so this second
// open gets a fresh one.
await reopenPopup(env, "main");
await openPrivkeyScreen(env.page); await openPrivkeyScreen(env.page);
await env.page.fill("#export-privkey-password", PASSWORD); await env.page.fill("#export-privkey-password", PASSWORD);
const inFlight = await env.page.evaluate(() => { const inFlight = await env.page.evaluate(() => {
+2 -38
View File
@@ -58,20 +58,7 @@ function makeElement(id, withParent) {
remove: () => {}, remove: () => {},
querySelectorAll: () => [], querySelectorAll: () => [],
}; };
el.parentElement = null; el.parentElement = withParent ? makeElement(id + "-parent", false) : null;
if (withParent) {
// As in a browser, replacing the parent's contents takes this
// element out of the document: getElementById no longer finds it.
el.parentElement = makeElement(id + "-parent", false);
let html = "";
Object.defineProperty(el.parentElement, "innerHTML", {
get: () => html,
set: (value) => {
html = value;
el.removed = true;
},
});
}
return el; return el;
} }
@@ -83,8 +70,7 @@ function makeDocument() {
// is the state a non-debug, non-testnet popup is in. // is the state a non-debug, non-testnet popup is in.
if (id === "debug-banner") return null; if (id === "debug-banner") return null;
if (!els.has(id)) els.set(id, makeElement(id, true)); if (!els.has(id)) els.set(id, makeElement(id, true));
const el = els.get(id); return els.get(id);
return el.removed ? null : el;
}, },
createElement: () => makeElement("created", false), createElement: () => makeElement("created", false),
addEventListener: () => {}, addEventListener: () => {},
@@ -314,28 +300,6 @@ describe("leaving the screen after the key is on it", () => {
}); });
}); });
describe("opening the screen again in the same popup session", () => {
// https://git.eeqj.de/sneak/AutistMask/issues/460: show() found the
// address line through an element inside it, which its own rendering
// deleted, so the second open threw before it navigated.
test("shows it for the address chosen the second time", async () => {
const { state, exportPrivkey } = load();
exportPrivkey.show(0, 0);
await click("btn-export-privkey-back");
expect(state.currentView).toBe("address");
exportPrivkey.show(0, 1);
expect(state.currentView).toBe(VIEW);
expect(node("export-privkey-title").textContent).toBe(
"Wallet 1 — Address 2",
);
expect(node("export-privkey-address").innerHTML).toContain(
"0x" + "22".repeat(20),
);
});
});
describe("views the popup may reopen onto", () => { describe("views the popup may reopen onto", () => {
// Restoring onto this screen would put a private key on display with no // Restoring onto this screen would put a private key on display with no
// password prompt in front of it, on a popup reopened by accident. // password prompt in front of it, on a popup reopened by accident.