Files
AutistMask/tests/addressScanCancelled.test.js
T
clawbot 447d714313
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run
fix: show every password error in its own fixed-height line (closes #493)
The add wallet screen reported a missing, short or mismatched password in
the flash line at the top of the popup, and the private key export,
recovery phrase and delete wallet screens each wrote to a line of their own
above the password field. All four now use showError() and hideError() with
a fixed-height error line below the field, as the send confirmation and
approval screens do. On the add wallet screen the line sits beside the
Import button, which keeps its place at 360x600. The line clears when the
screen is shown again and when the password is tried again. Other add
wallet messages stay in the flash line.

Model: opus-5-5
2026-10-07 10:59:16 +02:00

124 lines
4.0 KiB
JavaScript

// Creating a wallet from a recovery phrase or an extended private key does not
// report an address scan request the popup's own closing cancelled, and still
// reports one that failed while the popup was open
// (https://git.eeqj.de/sneak/AutistMask/issues/475).
//
// In the popup a cancelled request fails with the same "Failed to fetch" as a
// server that cannot be reached, so every RPC request here fails that way, and
// only the signal the popup aborts on pagehide tells the two cases apart.
// Driven against the fake elements tests/tokenLookupCancelled.test.js uses.
const { FetchRequest, HDNodeWallet, Mnemonic } = require("ethers");
const PHRASE =
"abandon abandon abandon abandon abandon abandon " +
"abandon abandon abandon abandon abandon about";
const PASSWORD = "correct horse battery staple";
let elements;
function fakeElement() {
return {
value: "",
textContent: "",
style: {},
classList: { toggle: () => {} },
listeners: {},
addEventListener(event, handler) {
this.listeners[event] = handler;
},
};
}
// Stands in for document.getElementById(): one fake element per id.
function element(id) {
return (elements[id] ||= fakeElement());
}
jest.doMock("../src/popup/views/helpers", () => ({
$: element,
showView: () => {},
showFlash: () => {},
showError: () => {},
hideError: () => {},
goBack: () => {},
clearViewStack: () => {},
onViewLeave: () => {},
}));
// state.js reads chrome.storage.local at load, and saveState() writes it.
globalThis.chrome = {
storage: { local: { get: async () => ({}), set: async () => {} } },
};
const { state } = require("../src/shared/state");
const addWallet = require("../src/popup/views/addWallet");
let logged;
beforeEach(() => {
elements = {};
logged = [];
state.wallets = [];
state.rpcUrl = "https://rpc.example.invalid";
state.networkId = "mainnet";
for (const method of ["warn", "error"]) {
jest.spyOn(console, method).mockImplementation((...args) => {
logged.push(args.map(String).join(" "));
});
}
// What the scan found is logged at info level, which is not under test.
jest.spyOn(console, "log").mockImplementation(() => {});
FetchRequest.registerGetUrl(async () => {
throw new TypeError("Failed to fetch");
});
});
afterEach(() => {
FetchRequest.registerGetUrl(FetchRequest.createGetUrlFunc());
jest.restoreAllMocks();
});
describe.each([
["a recovery phrase", "mnemonic", "wallet-mnemonic", PHRASE],
[
"an extended private key",
"xprv",
"import-xprv-key",
HDNodeWallet.fromSeed(Mnemonic.fromPhrase(PHRASE).computeSeed())
.extendedKey,
],
])("creating a wallet from %s", (_name, mode, field, secret) => {
// Enters `secret` on the add-wallet screen, presses its button and waits
// for the address scan that follows.
async function create(pageClosed) {
addWallet.init({
renderWalletList: () => {},
doRefreshAndRender: () => {},
pageClosed,
});
element("tab-" + mode).listeners.click();
element(field).value = secret;
element("add-wallet-password").value = PASSWORD;
element("add-wallet-password-confirm").value = PASSWORD;
await element("btn-add-wallet-confirm").listeners.click();
}
test("a scan failure while the popup is open is reported", async () => {
await create(new AbortController().signal);
expect(state.wallets).toHaveLength(1);
expect(logged).not.toEqual([]);
for (const line of logged) {
expect(line).toContain("scanForAddresses check failed");
}
});
test("a scan failure once the popup has closed is not", async () => {
const pageClosed = new AbortController();
pageClosed.abort();
await create(pageClosed.signal);
expect(state.wallets).toHaveLength(1);
expect(logged).toEqual([]);
});
});