From d9b8bc1d323ffb0927e2fbfa4dcb1dfe4ae065a7 Mon Sep 17 00:00:00 2001 From: sneak Date: Sun, 4 Oct 2026 09:22:44 +0000 Subject: [PATCH] fix: keep the dApp approval error containers to their reserved height (closes #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 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 --- TODO.md | 10 ++++++ src/popup/index.html | 4 +-- tests/e2e/run.js | 75 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index 00b7845..450f888 100644 --- a/TODO.md +++ b/TODO.md @@ -45,6 +45,16 @@ but the review is broader than any of them. # Completed Steps +- 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: The Send and confirmation screens no longer show an ETH balance, a token balance or a network fee below 0.000001 as zero ([#343](https://git.eeqj.de/sneak/AutistMask/issues/343)). The stored balances diff --git a/src/popup/index.html b/src/popup/index.html index 741bc1f..554f6be 100644 --- a/src/popup/index.html +++ b/src/popup/index.html @@ -1633,7 +1633,7 @@
@@ -1710,7 +1710,7 @@
diff --git a/tests/e2e/run.js b/tests/e2e/run.js index c3b61de..1a256c1 100644 --- a/tests/e2e/run.js +++ b/tests/e2e/run.js @@ -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