// Tests for the dust threshold field in Settings (issue #233). // // Two halves: what the parse accepts, and what the settings view does with a // rejection. The view half runs against the real change handler with the DOM // helpers stubbed out, because the bug was not in the parse — it was that a // rejection said nothing. const { DUST_THRESHOLD_MESSAGE, parseDustThresholdGwei, } = require("../src/popup/dustThreshold"); describe("parsing the dust threshold", () => { test("accepts a whole number of gwei", () => { expect(parseDustThresholdGwei("100000")).toBe(100000); expect(parseDustThresholdGwei("1")).toBe(1); }); // Zero is a real setting, not an empty field: it hides nothing. test("accepts zero", () => { expect(parseDustThresholdGwei("0")).toBe(0); }); test("accepts surrounding whitespace", () => { expect(parseDustThresholdGwei(" 250 ")).toBe(250); }); test("rejects an empty field", () => { expect(parseDustThresholdGwei("")).toBe(null); expect(parseDustThresholdGwei(" ")).toBe(null); }); test("rejects a negative threshold", () => { expect(parseDustThresholdGwei("-1")).toBe(null); }); // parseInt used to read this as 1, which is not what was typed. test("rejects a fractional value", () => { expect(parseDustThresholdGwei("1.5")).toBe(null); expect(parseDustThresholdGwei("1.0")).toBe(null); }); // parseInt used to read this as 100. The unit is printed beside the // field already. test("rejects a value carrying its unit", () => { expect(parseDustThresholdGwei("100 gwei")).toBe(null); }); // Number() reads this as 16. Storing 16 for a field that was told to // want a whole number of gwei would be the same silent substitution the // message exists to end. test("rejects hex notation", () => { expect(parseDustThresholdGwei("0x10")).toBe(null); }); // Number() reads this as 1000. test("rejects exponent notation", () => { expect(parseDustThresholdGwei("1e3")).toBe(null); }); test("rejects other non-numeric input", () => { expect(parseDustThresholdGwei("lots")).toBe(null); expect(parseDustThresholdGwei("+5")).toBe(null); expect(parseDustThresholdGwei("Infinity")).toBe(null); expect(parseDustThresholdGwei(undefined)).toBe(null); expect(parseDustThresholdGwei(5)).toBe(null); }); // Beyond 2^53 the digits would round on the way in, so the stored // threshold would not be the one typed. test("rejects a value too large to hold exactly", () => { expect(parseDustThresholdGwei("9007199254740993")).toBe(null); }); }); describe("the rejection message", () => { // README, Language & Labeling: error messages are full sentences. test("is a full sentence naming the constraint", () => { expect(DUST_THRESHOLD_MESSAGE).toMatch(/^[A-Z].*\.$/); expect(DUST_THRESHOLD_MESSAGE).toContain("whole number of gwei"); expect(DUST_THRESHOLD_MESSAGE).toContain("zero or greater"); }); }); describe("the flash line the message is shown in", () => { const fs = require("fs"); const path = require("path"); const POPUP_HTML = fs.readFileSync( path.join(__dirname, "..", "src", "popup", "index.html"), "utf8", ); // This asserts only that the reservation exists in the markup. It does // NOT and CANNOT assert that the message fits inside it: jest runs on // the node environment here, with no layout engine, so every rendered // height is zero. An earlier version of this block claimed to pin the // No Layout Shift policy with this regex, and it passed at any message // length, including one that wrapped to two lines and pushed the // settings view down 12px. // // The assertion that actually measures — empty line vs. the message, // real Chromium, documented 360x600 popup — is // "a rejected dust threshold shifts no layout (#233)" in // tests/e2e/run.js, run by make test-e2e. It is not in make check // because REPO_POLICIES.md caps make test at 20 seconds and a browser // suite does not fit; run it before changing the wording. test("reserves its height in the markup", () => { const flashLine = POPUP_HTML.match( /