Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a2d0b4a2a |
@@ -55,17 +55,6 @@ but the review is broader than any of them.
|
|||||||
later test in the run and cannot be removed, and moving the stored broadcast
|
later test in the run and cannot be removed, and moving the stored broadcast
|
||||||
time back can be undone by the save the popup makes every ten seconds.
|
time back can be undone by the save the popup makes every ten seconds.
|
||||||
|
|
||||||
- 2026-10-05: The Chrome end-to-end suite covers the last of the
|
|
||||||
[#150](https://git.eeqj.de/sneak/AutistMask/issues/150) and
|
|
||||||
[#151](https://git.eeqj.de/sneak/AutistMask/issues/151) items
|
|
||||||
([#295](https://git.eeqj.de/sneak/AutistMask/issues/295)): a token added on
|
|
||||||
Add Token by its contract address is listed on the address screen;
|
|
||||||
TransactionDetail opened from the token screen leaves that screen on the
|
|
||||||
persisted navigation stack, and Back returns to it; and the token contract row
|
|
||||||
links to the explorer's token page, read off the link rather than followed.
|
|
||||||
The network stub answers `symbol()` and `name()` for the stub token, which
|
|
||||||
adding it reads.
|
|
||||||
|
|
||||||
- 2026-10-05: Each control that leads to a signature or to the private key has a
|
- 2026-10-05: Each control that leads to a signature or to the private key has a
|
||||||
test that it refuses a defective wallet before asking for a password
|
test that it refuses a defective wallet before asking for a password
|
||||||
([#254](https://git.eeqj.de/sneak/AutistMask/issues/254)): Send on the main,
|
([#254](https://git.eeqj.de/sneak/AutistMask/issues/254)): Send on the main,
|
||||||
|
|||||||
+6
-18
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { AbiCoder, Transaction } = require("ethers");
|
const { Transaction } = require("ethers");
|
||||||
|
|
||||||
// Fictional ERC-20 used to seed the transaction-detail test. The symbol
|
// Fictional ERC-20 used to seed the transaction-detail test. The symbol
|
||||||
// must not collide with any entry in src/shared/tokenList.js, or
|
// must not collide with any entry in src/shared/tokenList.js, or
|
||||||
@@ -244,16 +244,12 @@ function latestBlock() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// keccak("decimals()")[0:4], and the same for symbol() and name().
|
// keccak("decimals()")[0:4].
|
||||||
const SELECTOR_DECIMALS = "0x313ce567";
|
const SELECTOR_DECIMALS = "0x313ce567";
|
||||||
const SELECTOR_SYMBOL = "0x95d89b41";
|
|
||||||
const SELECTOR_NAME = "0x06fdde03";
|
|
||||||
|
|
||||||
// Every eth_call still answers with a zero word except decimals(), symbol()
|
// Every eth_call still answers with a zero word except decimals() on the
|
||||||
// and name() on the stub token. The wallet reads decimals() back at signing
|
// stub token, which the wallet reads back at signing time to compare with
|
||||||
// time to compare with the scale the confirmation screen rendered (issue
|
// the scale the confirmation screen rendered (issue #305).
|
||||||
// #305). Adding the token by its contract address reads all three (issue
|
|
||||||
// #295); symbol() and name() answer what the explorer reports for it.
|
|
||||||
//
|
//
|
||||||
// opts.tokenDecimalsOverride is the lying contract: set it and decimals()
|
// opts.tokenDecimalsOverride is the lying contract: set it and decimals()
|
||||||
// answers something other than the value this same fixture reports through
|
// answers something other than the value this same fixture reports through
|
||||||
@@ -267,17 +263,9 @@ function ethCallResult(req, opts) {
|
|||||||
if (!call || typeof call !== "object") return ZERO_WORD;
|
if (!call || typeof call !== "object") return ZERO_WORD;
|
||||||
const data = String(call.data || call.input || "").toLowerCase();
|
const data = String(call.data || call.input || "").toLowerCase();
|
||||||
const to = String(call.to || "").toLowerCase();
|
const to = String(call.to || "").toLowerCase();
|
||||||
if (to !== STUB_TOKEN.address) return ZERO_WORD;
|
if (data.startsWith(SELECTOR_DECIMALS) && to === STUB_TOKEN.address) {
|
||||||
if (data.startsWith(SELECTOR_DECIMALS)) {
|
|
||||||
return word(opts.tokenDecimalsOverride ?? STUB_TOKEN.decimals);
|
return word(opts.tokenDecimalsOverride ?? STUB_TOKEN.decimals);
|
||||||
}
|
}
|
||||||
const abi = AbiCoder.defaultAbiCoder();
|
|
||||||
if (data.startsWith(SELECTOR_SYMBOL)) {
|
|
||||||
return abi.encode(["string"], [tokenObject(opts).symbol]);
|
|
||||||
}
|
|
||||||
if (data.startsWith(SELECTOR_NAME)) {
|
|
||||||
return abi.encode(["string"], [tokenObject(opts).name]);
|
|
||||||
}
|
|
||||||
return ZERO_WORD;
|
return ZERO_WORD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -596,106 +596,6 @@ test("tap-to-copy on the transaction detail screen copies the address (#151)", a
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// ------------------------- the last of the #150 and #151 items (#295)
|
|
||||||
//
|
|
||||||
// Add Token's confirm button, TransactionDetail opened from the token screen
|
|
||||||
// and Back from it, and the explorer link on the token contract row.
|
|
||||||
|
|
||||||
// The stub token stays tracked for the rest of the run: the next test reaches
|
|
||||||
// its token screen through the balance row this one adds.
|
|
||||||
test("a token added by its contract address is listed on the address screen (#150)", async (env) => {
|
|
||||||
await leaveTransactionDetail(env.page);
|
|
||||||
await env.page.click("#btn-add-token");
|
|
||||||
await visible(env.page, "#view-add-token");
|
|
||||||
|
|
||||||
await env.page.fill("#add-token-address", STUB_TOKEN.address);
|
|
||||||
await env.page.click("#btn-add-token-confirm");
|
|
||||||
await visible(env.page, "#view-address");
|
|
||||||
|
|
||||||
// No wait: the confirm renders the balance list before it shows the
|
|
||||||
// screen, and nothing renders the list again while the screen is up.
|
|
||||||
const row = env.page.locator(
|
|
||||||
'#address-balances [data-token="' + STUB_TOKEN.address + '"]',
|
|
||||||
{ hasText: STUB_TOKEN.symbol },
|
|
||||||
);
|
|
||||||
const balances = await env.page.locator("#address-balances").innerText();
|
|
||||||
assert(
|
|
||||||
(await row.count()) === 1,
|
|
||||||
"the balance list has no " +
|
|
||||||
STUB_TOKEN.symbol +
|
|
||||||
" row for the token just added: " +
|
|
||||||
JSON.stringify(balances),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// TransactionDetail looks the same from either entry point. Only the
|
|
||||||
// persisted stack says which one opened it, so that is what is asserted: from
|
|
||||||
// the token screen it ends in "address-token", and Back has to land there
|
|
||||||
// rather than on the address screen beneath it.
|
|
||||||
test("transaction detail opened from the token screen goes Back to it (#151)", async (env) => {
|
|
||||||
await goHome(env.page);
|
|
||||||
const base = await persistedViewStack(env.page);
|
|
||||||
|
|
||||||
await env.page.locator("#wallet-list .btn-addr-info").first().click();
|
|
||||||
await visible(env.page, "#view-address");
|
|
||||||
await env.page
|
|
||||||
.locator('#address-balances [data-token="' + STUB_TOKEN.address + '"]')
|
|
||||||
.click();
|
|
||||||
await visible(env.page, "#view-address-token");
|
|
||||||
|
|
||||||
const row = env.page.locator("#address-token-tx-list .tx-row").first();
|
|
||||||
await row.waitFor({ state: "visible", timeout: 30000 });
|
|
||||||
await row.click();
|
|
||||||
await visible(env.page, "#view-transaction");
|
|
||||||
await waitForPersisted(
|
|
||||||
env.page,
|
|
||||||
"viewStack",
|
|
||||||
base.concat("main", "address", "address-token"),
|
|
||||||
"on transaction detail opened from the token screen",
|
|
||||||
);
|
|
||||||
|
|
||||||
// The stack is checked before the screen, so a Back that lands on the
|
|
||||||
// wrong screen fails by saying what the stack holds.
|
|
||||||
await env.page.click("#btn-tx-back");
|
|
||||||
await waitForPersisted(
|
|
||||||
env.page,
|
|
||||||
"viewStack",
|
|
||||||
base.concat("main", "address"),
|
|
||||||
"after Back from transaction detail",
|
|
||||||
);
|
|
||||||
await visible(env.page, "#view-address-token");
|
|
||||||
|
|
||||||
// Onto the address screen, which the next test starts from.
|
|
||||||
await env.page.click("#btn-address-token-back");
|
|
||||||
await visible(env.page, "#view-address");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Read off the anchor rather than followed: where it points is all the popup
|
|
||||||
// decides, and following it would only load the explorer's page. The suite is
|
|
||||||
// on mainnet until the Settings section.
|
|
||||||
test("the token contract row links to the explorer's token page (#151)", async (env) => {
|
|
||||||
await leaveTransactionDetail(env.page);
|
|
||||||
const row = env.page
|
|
||||||
.locator("#tx-list .tx-row")
|
|
||||||
.filter({ hasText: STUB_TOKEN.symbol });
|
|
||||||
await row.waitFor({ state: "visible", timeout: 30000 });
|
|
||||||
await row.click();
|
|
||||||
await visible(env.page, "#view-transaction");
|
|
||||||
await visible(env.page, "#tx-detail-token-contract-section");
|
|
||||||
|
|
||||||
const href = await env.page
|
|
||||||
.locator("#tx-detail-token-contract a")
|
|
||||||
.getAttribute("href");
|
|
||||||
const expected = "https://etherscan.io/token/" + STUB_TOKEN.address;
|
|
||||||
assert(
|
|
||||||
href === expected,
|
|
||||||
"the token contract row links to " +
|
|
||||||
JSON.stringify(href) +
|
|
||||||
", expected " +
|
|
||||||
expected,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// -------------------------------------------- recovery phrase (#161)
|
// -------------------------------------------- recovery phrase (#161)
|
||||||
|
|
||||||
// The gear toggles, so pressing it while Settings is already up leaves it.
|
// The gear toggles, so pressing it while Settings is already up leaves it.
|
||||||
|
|||||||
Reference in New Issue
Block a user