diff --git a/tests/popupBoot.test.js b/tests/popupBoot.test.js index bbc0067..5980cbf 100644 --- a/tests/popupBoot.test.js +++ b/tests/popupBoot.test.js @@ -9,6 +9,7 @@ const { bootPopup, cleanupPopup, unversionedValidProfile, + ADDRESS, } = require("./support/popupBoot"); const FLASH_MS = 10; @@ -40,3 +41,47 @@ test("a flash message's timer does not fire after cleanupPopup()", async () => { await wait(FLASH_MS * 5); }); + +// A boot onto a screen whose requests no mocked module answers: they reach the +// boot's fetch() stub, never the internet +// (https://git.eeqj.de/sneak/AutistMask/issues/559). +function restoringOnto(view, viewData) { + return unversionedValidProfile({ + currentView: view, + selectedWallet: 0, + selectedAddress: 0, + viewStack: ["main"], + viewData, + }); +} + +test("the transaction screen's Blockscout request reaches the stub", async () => { + const page = await bootPopup( + restoringOnto("transaction", { + tx: { hash: "0x1", from: ADDRESS, to: ADDRESS }, + }), + ); + + expect(page.visibleViews()).toEqual(["transaction"]); + expect(globalThis.fetch.mock.calls.map((call) => call[0])).toEqual([ + "https://eth.blockscout.com/api/v2/transactions/0x1", + ]); +}); + +test("the confirmation screen's Etherscan lookup reaches the stub", async () => { + const page = await bootPopup( + restoringOnto("confirm-tx", { + pendingTx: { + token: "ETH", + from: ADDRESS, + to: ADDRESS, + amount: "1", + }, + }), + ); + + expect(page.visibleViews()).toEqual(["confirm-tx"]); + expect(globalThis.fetch.mock.calls.map((call) => call[0])).toEqual([ + "https://etherscan.io/address/" + ADDRESS, + ]); +}); diff --git a/tests/support/popupBoot.js b/tests/support/popupBoot.js index 02f98d0..b2c6c6b 100644 --- a/tests/support/popupBoot.js +++ b/tests/support/popupBoot.js @@ -45,6 +45,7 @@ const realSetInterval = globalThis.setInterval; const realClearInterval = globalThis.clearInterval; const realSetTimeout = globalThis.setTimeout; const realClearTimeout = globalThis.clearTimeout; +const realFetch = globalThis.fetch; // Every timeout set since the last cleanupPopup() that has neither fired nor // been cleared. cleanupPopup() clears them all. @@ -260,8 +261,10 @@ async function settle() { async function bootPopup(stored, options) { jest.resetModules(); - // The three modules that reach the network. None is on the path under - // test; all would make the suite hit the internet. + // Three of the modules that reach the network. None is on the path under + // test; all would make the suite hit the internet. Every other request, + // such as the transaction screen's Blockscout lookup and the Etherscan + // lookup in src/shared/etherscanLabels.js, meets the fetch() stub below. jest.doMock("../../src/shared/prices", () => ({ prices: {}, refreshPrices: jest.fn(async () => {}), @@ -334,6 +337,12 @@ async function bootPopup(stored, options) { windowListeners[name].push(fn); }, }; + // Every fetch() the page makes fails, as it does elsewhere in the suite, + // instead of reaching the internet. A new stub per boot, so its calls are + // that boot's requests. Put back by cleanupPopup(). + globalThis.fetch = jest.fn(() => { + throw new Error("tests must not perform network requests"); + }); // The ten-second refresh init() starts, and a transaction wait's timers, // would outlive the test. So every interval is recorded rather than // started, clearInterval() removes it as a browser would, and tick() below @@ -435,6 +444,7 @@ function cleanupPopup() { pendingTimeouts.clear(); globalThis.setTimeout = realSetTimeout; globalThis.clearTimeout = realClearTimeout; + globalThis.fetch = realFetch; } module.exports = {