Compare commits

..
3 Commits
Author SHA1 Message Date
sneak ad19d1aab3 fix: decode Uniswap V2 exact-out swaps, input amount shown as a maximum (closes #283)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run
decode() had no arm for Universal Router command 0x09, so the approval
screen showed no token or amount for it. It now takes the path's first
token and amountInMax as the input side, the last token and amountOut as
the output side. With such a step, the Amount figure reads "Up to
<amount>" whichever step set it, on the approval, wait, success and error
screens, unless it reads "Unlimited", as an unbounded PERMIT2_PERMIT does,
or "All available (V4 open delta)". In every swap, UNWRAP_WETH makes
Token Out ETH only when the output side is WETH, on mainnet or Sepolia, or
no step set it; otherwise the output keeps its own token and figure.
decodeV2SwapExactOut() loses its eslint-disable comment.

Model: opus-5-5
2026-10-04 12:43:40 +00:00
clawbot 43c236451f chore: run jest in three worker processes (closes #426)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run
The test and test:verbose scripts ran jest with one worker per CPU core,
about 47 processes and 7-8 GiB per run on the shared 48-core build host.
They now pass --maxWorkers=3. On that host the suite takes 23-29s, inside
the unchanged 30-second cap in script/test but not by much: one test
file, tests/persistedFieldContract.test.js, takes most of it. One or two
workers went past the cap, so this departs from the issue's two-process
limit. make check, the pre-commit hook and script/cibuild all reach jest
through these scripts; the timings in the script/test and Dockerfile
comments are updated to match.

Model: opus-5-5
2026-10-04 14:26:03 +02:00
clawbot 1247c24c4d fix: keep the dApp approval error containers to their reserved height (closes #297)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run
#approve-tx-error and #approve-sign-error reserved 20px, but their border
and padding took 10px of it, so a one-line error grew them to 26px and
pushed the Confirm/Sign buttons down 6px. They now reserve 30px, the same
4px to spare over one line that the other password error containers have.

A new end-to-end test shows each of the six password error containers on
its own screen at the popup viewport, empty and then with an error, and
fails if one changes height or the element below it moves.

Model: opus-5-5
2026-10-04 12:58:26 +02:00
6 changed files with 113 additions and 14 deletions
+3 -3
View File
@@ -9,9 +9,9 @@ WORKDIR /app
ENV AUTISTMASK_LINT_NATIVE=1
# script/test's default 30s bound is the host figure, against a suite that
# runs in about 8s there. In here the same suite starts on a cold jest cache
# and shares the runner with the rest of the build, so 30s is marginal rather
# than a bound — it killed a healthy suite at 30.6s on a cold CI cache. 180s
# takes 23-29s there with three jest workers. In here the same suite starts on
# a cold jest cache and shares the runner with the rest of the build, so 30s
# is too tight — it killed a healthy suite at 30.6s on a cold CI cache. 180s
# still catches a hang in three minutes and cannot be tripped by a suite that
# is merely running on contended hardware.
ENV AUTISTMASK_TEST_TIMEOUT=180
+21
View File
@@ -60,6 +60,27 @@ but the review is broader than any of them.
`Token Out` and `Min. received` keep the output side's own token and figure.
V3 exact-out (`0x01`) is still not decoded.
- 2026-10-04: `make test` runs jest in three worker processes
([#426](https://git.eeqj.de/sneak/AutistMask/issues/426)). The `test` and
`test:verbose` scripts in `package.json` ran `jest --forceExit`, which starts
one worker per CPU core: about 47 processes and 7-8 GiB per run on the shared
48-core build host. They now pass `--maxWorkers=3`, and the suite takes 23-29s
there: inside the 30-second cap in `script/test`, which is unchanged, but not
by much, because `tests/persistedFieldContract.test.js` alone takes most of it
([#428](https://git.eeqj.de/sneak/AutistMask/issues/428)). One or two workers
went past the cap. `make check`, the pre-commit hook and `script/cibuild` all
run the suite through these scripts.
- 2026-10-04: The error container on each dApp approval screen keeps its height
when an error appears
([#297](https://git.eeqj.de/sneak/AutistMask/issues/297)). `#approve-tx-error`
and `#approve-sign-error` reserved 20px, but their border and padding took
10px of it, so a one-line error grew them to 26px and pushed the buttons below
down 6px. They now reserve 30px. A new test in `tests/e2e/run.js` shows each
of the six password error containers on its own screen, empty and then with an
error, and fails if one changes height or the element below it moves. Some of
the longer messages these two containers can show still take two lines.
- 2026-10-04: A transaction with no `to` says "This transaction creates a new
contract. It has no recipient." on its recipient line and in its transaction
history row ([#250](https://git.eeqj.de/sneak/AutistMask/issues/250)). The
+2 -2
View File
@@ -6,8 +6,8 @@
"license": "GPL-3.0",
"private": true,
"scripts": {
"test": "jest --forceExit",
"test:verbose": "jest --forceExit --verbose",
"test": "jest --forceExit --maxWorkers=3",
"test:verbose": "jest --forceExit --maxWorkers=3 --verbose",
"build": "node build.js",
"lint": "eslint . && prettier --check .",
"fmt": "prettier --write .",
+10 -7
View File
@@ -1,13 +1,16 @@
#!/bin/sh
# script/test: run the test suite.
#
# The timeout bounds a hung suite; it is not a performance budget. On a
# developer host the suite finishes in about 8s and REPO_POLICIES' 30s cap is
# the bound. Inside the image the same suite also pays a cold jest cache and
# shares the runner with the rest of the build, which is not what that budget
# describes, so the Dockerfile raises the bound through
# AUTISTMASK_TEST_TIMEOUT. A cap a healthy suite can trip on a cold cache
# produces a red that means nothing, and teaches "just run it again".
# jest runs three worker processes (package.json), not one per CPU core: on a
# many-core shared host one per core took gigabytes of RAM per run.
#
# The timeout bounds a hung suite; it is not a performance budget. On the busy
# shared build host the suite takes 23-29s with three workers, so
# REPO_POLICIES' 30s cap is tight there, not comfortable. Inside the image the
# same suite also pays a cold jest cache and shares the runner with the rest of
# the build, which is not what that budget describes, so the Dockerfile raises
# the bound through AUTISTMASK_TEST_TIMEOUT. A cap a healthy suite can trip on a
# cold cache produces a red that means nothing, and teaches "just run it again".
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
+2 -2
View File
@@ -1633,7 +1633,7 @@
</div>
<div
id="approve-tx-error"
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.25rem]"
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.875rem]"
style="visibility: hidden"
></div>
<div class="flex justify-between">
@@ -1710,7 +1710,7 @@
</div>
<div
id="approve-sign-error"
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.25rem]"
class="text-xs mb-2 border border-border border-dashed p-1 min-h-[1.875rem]"
style="visibility: hidden"
></div>
<div class="flex justify-between">
+75
View File
@@ -1449,6 +1449,81 @@ test("an over-long flash message keeps to one line (#252)", async (env) => {
}
});
// --------------------------------------- password error containers (#297)
// Every screen that asks for a password reserves room for one line of error.
// The two on the dApp approval screens also have a border and padding, which
// that reserved height has to cover too.
const PASSWORD_ERROR_CONTAINERS = [
"approve-tx-error",
"approve-sign-error",
"export-privkey-flash",
"show-phrase-flash",
"delete-wallet-flash",
"confirm-tx-password-error",
];
// Shows only the screen holding the container, then measures the container
// and the element below it empty and again filled the way showError() in
// src/popup/views/helpers.js fills it. Runs in the page.
function measurePasswordError(id) {
const container = document.getElementById(id);
const screen = container.closest(".view");
for (const view of document.querySelectorAll(".view")) {
view.classList.toggle("hidden", view !== screen);
}
const below = container.nextElementSibling;
const measure = () => ({
height: container.getBoundingClientRect().height,
belowTop: below.getBoundingClientRect().top + window.scrollY,
belowHeight: below.getBoundingClientRect().height,
});
const empty = measure();
container.textContent = "Please enter your password.";
container.style.visibility = "visible";
const filled = measure();
container.textContent = "";
container.style.visibility = "hidden";
return { empty, filled };
}
test("a password error moves nothing on any screen (#297)", async (env) => {
const page = await openPopup(env.ctx, env.popupUrl);
try {
await page.setViewportSize(POPUP_VIEWPORT);
for (const id of PASSWORD_ERROR_CONTAINERS) {
const { empty, filled } = await page.evaluate(
measurePasswordError,
id,
);
assert(
empty.belowHeight > 0,
"nothing is shown below #" + id + ", so nothing was measured",
);
assert(
filled.height === empty.height,
"#" +
id +
" is " +
empty.height +
"px empty and " +
filled.height +
"px with an error",
);
assert(
filled.belowTop === empty.belowTop,
"the element below #" +
id +
" moved " +
(filled.belowTop - empty.belowTop) +
"px when the error appeared",
);
}
} finally {
await page.close();
}
});
// --------------------------------------------- confirmation screen (#238)
//
// The screen that decides what gets signed. The arithmetic underneath it