fix: a popup reload no longer logs the requests it cancels, except on the transaction detail and confirmation screens (closes #475)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run

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
This commit is contained in:
2026-10-06 12:34:54 +00:00
parent 329e64a54d
commit f8f2461354
20 changed files with 577 additions and 49 deletions
+47 -8
View File
@@ -249,8 +249,23 @@ test("the exact confirmation phrase erases the record and reloads into Welcome (
}
});
test("wallet creation through the UI reaches the main view", async (env) => {
env.phrase = await createWallet(env.page);
// The address scan that follows creating the wallet is held, so the popup
// reloads while it is in flight. As for the reloads mid-refresh further down,
// the assertion for that is the harness's own: a console.error from the page
// being reloaded fails this test (#475).
test("wallet creation through the UI reaches the main view, and reloading mid-scan reports no failure (#475)", async (env) => {
env.routeOpts.holdTransactionCount = true;
try {
const scanning = env.page.waitForRequest((r) =>
(r.postData() || "").includes("eth_getTransactionCount"),
);
env.phrase = await createWallet(env.page);
await scanning;
await env.page.reload();
} finally {
env.routeOpts.holdTransactionCount = false;
}
await visible(env.page, "#view-main");
assert(
env.phrase.split(/\s+/).length >= 12,
"wallet creation did not yield a recovery phrase",
@@ -700,9 +715,8 @@ test("the token contract row links to the explorer's token page (#151)", async (
//
// Reloading or closing the popup makes Chrome cancel the requests it still has
// open, and in the page a cancelled fetch() fails with the same "Failed to
// fetch" as a server that cannot be reached. Here rather than straight after
// wallet creation because a reload also cancels the address scan that follows
// it, which still logs (#475).
// fetch" as a server that cannot be reached. The reload during the address
// scan that follows creating a wallet is in the wallet creation test (#475).
// Blockscout is held, so the home screen's transaction list and token balances
// cannot have been answered when the popup reloads. The assertion is the
@@ -752,6 +766,30 @@ test("a transaction list that cannot be fetched is still reported (#218)", async
}
});
// The address screen's transaction list, held the same way. The popup reopens
// on the address screen, which asks for its list as it is drawn, so once the
// screen is up its request is in flight (#475).
test("reloading the popup on the address screen reports no failure (#475)", async (env) => {
await openAddressDetail(env.page);
await waitForPersisted(
env.page,
"currentView",
"address",
"before reloading the popup",
);
env.routeOpts.holdBlockscout = true;
try {
await env.page.reload();
await visible(env.page, "#view-address");
await env.page.reload();
} finally {
env.routeOpts.holdBlockscout = false;
}
await visible(env.page, "#view-address");
// Home again, where the tests below expect to start.
await goHome(env.page);
});
// -------------------------------------------- recovery phrase (#161)
// The gear toggles, so pressing it while Settings is already up leaves it.
@@ -2163,9 +2201,7 @@ function quantity(wei) {
// Wait on the main view until a changed balance fixture has been picked up.
//
// Not a reload: the popup re-refreshes on a 10-second timer by itself, and a
// reload on the address screen still logs the transaction list it cancels
// (#475).
// Not a reload: the popup re-refreshes on a 10-second timer by itself.
//
// It also deliberately settles on MAIN rather than on the address screen.
// The address screen builds the send screen's token dropdown once, from the
@@ -4525,6 +4561,9 @@ async function main() {
ethBalanceWei: null,
failGasEstimate: false,
holdGasEstimate: false,
// Whether a JSON-RPC batch asking for a transaction count is held
// unanswered: the address scan after creating a wallet (#475).
holdTransactionCount: false,
// Whether Blockscout requests are held unanswered, and whether an
// address's transaction list fails as a network error (#218).
holdBlockscout: false,