// Another page stores a different RPC or Blockscout URL for the same network. // Then the user taps "Save" in Settings on this page, on the URL that this page // loaded. The URL on screen is stored, and the flash message reads "Saved." // (https://git.eeqj.de/sneak/AutistMask/issues/688). Driven through the real // popup over a stored profile on Ethereum Mainnet. const { bootPopup, cleanupPopup, unversionedValidProfile, } = require("./support/popupBoot"); const { NETWORKS } = require("../src/shared/networks"); afterEach(() => { cleanupPopup(); }); test.each([ { button: "btn-save-rpc", input: "settings-rpc", field: "rpcUrl" }, { button: "btn-save-blockscout", input: "settings-blockscout", field: "blockscoutUrl", }, ])( "$button stores the URL on screen after another page stored a different one", async ({ button, input, field }) => { const page = await bootPopup(unversionedValidProfile()); await page.click("btn-settings"); const url = page.value(input); // This write sends this page no storage change event. page.storage.write("autistmask", { ...page.storage.read("autistmask"), [field]: "https://other-page.example.invalid", }); // This answer passes both endpoint checks on Ethereum Mainnet. The RPC // check reads Ethereum Mainnet's chain id from it. The Blockscout check // reads `ok`. globalThis.fetch.mockResolvedValue({ ok: true, json: async () => ({ result: NETWORKS.mainnet.chainId }), }); await page.click(button); expect(page.storage.read("autistmask")[field]).toBe(url); expect(page.text("flash-msg")).toBe("Saved."); }, ); // The user types a URL in Settings and taps "Save". While the check waits for // the endpoint's answer, another page turns "Use Blockscout" on. This page // follows that change and draws Settings again, with the stored URL in the // field. The check then passes. The typed URL is not stored, and the flash // message never reads "Saved." // (https://git.eeqj.de/sneak/AutistMask/issues/695). test.each([ { button: "btn-save-rpc", input: "settings-rpc", field: "rpcUrl" }, { button: "btn-save-blockscout", input: "settings-blockscout", field: "blockscoutUrl", }, ])( "$button stores nothing when Settings is drawn again during the check", async ({ button, input, field }) => { const page = await bootPopup(unversionedValidProfile()); await page.click("btn-settings"); const storedUrl = page.value(input); let answer; globalThis.fetch.mockReturnValue( new Promise((resolve) => { answer = resolve; }), ); page.node(input).value = "https://typed.example.invalid"; const saving = page.node(button).listeners.click.map((fn) => fn()); await page.settle(); // The browser announces this write to this page. await page.storage.local.set({ autistmask: { ...page.storage.read("autistmask"), useBlockscout: true, }, }); await page.settle(); expect(page.node("settings-use-blockscout").checked).toBe(true); // This answer passes both endpoint checks on Ethereum Mainnet. answer({ ok: true, json: async () => ({ result: NETWORKS.mainnet.chainId }), }); await Promise.all(saving); await page.settle(); expect(page.storage.read("autistmask")[field]).toBe(storedUrl); expect(page.value(input)).toBe(storedUrl); expect(page.text("flash-msg")).not.toBe("Saved."); }, );