test: the popup boot in the jest suite sends no request to the internet #597
@@ -9,6 +9,7 @@ const {
|
|||||||
bootPopup,
|
bootPopup,
|
||||||
cleanupPopup,
|
cleanupPopup,
|
||||||
unversionedValidProfile,
|
unversionedValidProfile,
|
||||||
|
ADDRESS,
|
||||||
} = require("./support/popupBoot");
|
} = require("./support/popupBoot");
|
||||||
|
|
||||||
const FLASH_MS = 10;
|
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);
|
await wait(FLASH_MS * 5);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// A boot onto a screen that sends a request no mocked module answers: that
|
||||||
|
// request reaches 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,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ const realSetInterval = globalThis.setInterval;
|
|||||||
const realClearInterval = globalThis.clearInterval;
|
const realClearInterval = globalThis.clearInterval;
|
||||||
const realSetTimeout = globalThis.setTimeout;
|
const realSetTimeout = globalThis.setTimeout;
|
||||||
const realClearTimeout = globalThis.clearTimeout;
|
const realClearTimeout = globalThis.clearTimeout;
|
||||||
|
const realFetch = globalThis.fetch;
|
||||||
|
|
||||||
// Every timeout set since the last cleanupPopup() that has neither fired nor
|
// Every timeout set since the last cleanupPopup() that has neither fired nor
|
||||||
// been cleared. cleanupPopup() clears them all.
|
// been cleared. cleanupPopup() clears them all.
|
||||||
@@ -260,8 +261,14 @@ async function settle() {
|
|||||||
async function bootPopup(stored, options) {
|
async function bootPopup(stored, options) {
|
||||||
jest.resetModules();
|
jest.resetModules();
|
||||||
|
|
||||||
// The three modules that reach the network. None is on the path under
|
// The RPC requests made through src/shared/balances.js go through Node's
|
||||||
// test; all would make the suite hit the internet.
|
// own http and https modules, not fetch(), so the fetch() stub below would
|
||||||
|
// not stop them, which is why that module stays mocked.
|
||||||
|
// src/shared/prices.js and src/shared/transactions.js send their requests
|
||||||
|
// through fetch(), and their mocks answer with no prices and no
|
||||||
|
// transactions. Every request the page still sends, such as the
|
||||||
|
// transaction screen's Blockscout lookup and the Etherscan lookup in
|
||||||
|
// src/shared/etherscanLabels.js, meets the fetch() stub.
|
||||||
jest.doMock("../../src/shared/prices", () => ({
|
jest.doMock("../../src/shared/prices", () => ({
|
||||||
prices: {},
|
prices: {},
|
||||||
refreshPrices: jest.fn(async () => {}),
|
refreshPrices: jest.fn(async () => {}),
|
||||||
@@ -334,6 +341,12 @@ async function bootPopup(stored, options) {
|
|||||||
windowListeners[name].push(fn);
|
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 the calls it
|
||||||
|
// records start with that boot. 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,
|
// The ten-second refresh init() starts, and a transaction wait's timers,
|
||||||
// would outlive the test. So every interval is recorded rather than
|
// would outlive the test. So every interval is recorded rather than
|
||||||
// started, clearInterval() removes it as a browser would, and tick() below
|
// started, clearInterval() removes it as a browser would, and tick() below
|
||||||
@@ -435,6 +448,7 @@ function cleanupPopup() {
|
|||||||
pendingTimeouts.clear();
|
pendingTimeouts.clear();
|
||||||
globalThis.setTimeout = realSetTimeout;
|
globalThis.setTimeout = realSetTimeout;
|
||||||
globalThis.clearTimeout = realClearTimeout;
|
globalThis.clearTimeout = realClearTimeout;
|
||||||
|
globalThis.fetch = realFetch;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
Reference in New Issue
Block a user