test: no timer a popup test started fires after cleanupPopup() (closes #578)
tests/support/popupBoot.js recorded every interval the popup sets but left timeouts alone, so the two-second timer that clears a flash message could fire after cleanupPopup() had removed the page, throw "document is not defined", and fail whichever test file the jest worker had moved on to. Timeouts still run for real during a popup test; the helper now records each one until it fires or is cleared, and cleanupPopup() clears the ones still pending. The fake timers tests/firstWalletRefresh.test.js used to hold that timer are removed. tests/popupBoot.test.js shows a flash message, cleans up, waits past the flash duration, and fails if anything throws. Model: opus-5-5
This commit was merged in pull request #582.
This commit is contained in:
@@ -61,16 +61,12 @@ async function importOn(page, { tab, field, secret }) {
|
|||||||
await page.click("btn-add-wallet-confirm");
|
await page.click("btn-add-wallet-confirm");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fake timers hold the timer of the flash message an import ends with, which
|
|
||||||
// would otherwise fire after cleanupPopup() has removed the page and throw.
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.useFakeTimers();
|
|
||||||
chainBalance = "0.0";
|
chainBalance = "0.0";
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cleanupPopup();
|
cleanupPopup();
|
||||||
jest.useRealTimers();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("a popup that opened on Welcome", () => {
|
describe("a popup that opened on Welcome", () => {
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// A timer the popup started and that fires after cleanupPopup() has removed
|
||||||
|
// the page throws "document is not defined", and the throw fails whatever test
|
||||||
|
// the jest worker is running by then, in this file or another
|
||||||
|
// (https://git.eeqj.de/sneak/AutistMask/issues/578). The flash message's
|
||||||
|
// timer is the one that did it. A throw from a timer during a test fails that
|
||||||
|
// test, so each test here passes only if nothing throws.
|
||||||
|
|
||||||
|
const {
|
||||||
|
bootPopup,
|
||||||
|
cleanupPopup,
|
||||||
|
unversionedValidProfile,
|
||||||
|
} = require("./support/popupBoot");
|
||||||
|
|
||||||
|
const FLASH_MS = 10;
|
||||||
|
|
||||||
|
function wait(ms) {
|
||||||
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
cleanupPopup();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("a flash message clears while the page is up", async () => {
|
||||||
|
const page = await bootPopup(unversionedValidProfile());
|
||||||
|
const { showFlash } = require("../src/popup/views/helpers");
|
||||||
|
showFlash("Copied.", FLASH_MS);
|
||||||
|
expect(page.text("flash-msg")).toBe("Copied.");
|
||||||
|
|
||||||
|
await wait(FLASH_MS * 5);
|
||||||
|
|
||||||
|
expect(page.text("flash-msg")).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("a flash message's timer does not fire after cleanupPopup()", async () => {
|
||||||
|
await bootPopup(unversionedValidProfile());
|
||||||
|
const { showFlash } = require("../src/popup/views/helpers");
|
||||||
|
showFlash("Copied.", FLASH_MS);
|
||||||
|
cleanupPopup();
|
||||||
|
|
||||||
|
await wait(FLASH_MS * 5);
|
||||||
|
});
|
||||||
@@ -43,6 +43,12 @@ jest.doMock("ethereum-blockies-base64", () => makeBlockie);
|
|||||||
// Taken before any boot replaces them; see bootPopup().
|
// Taken before any boot replaces them; see bootPopup().
|
||||||
const realSetInterval = globalThis.setInterval;
|
const realSetInterval = globalThis.setInterval;
|
||||||
const realClearInterval = globalThis.clearInterval;
|
const realClearInterval = globalThis.clearInterval;
|
||||||
|
const realSetTimeout = globalThis.setTimeout;
|
||||||
|
const realClearTimeout = globalThis.clearTimeout;
|
||||||
|
|
||||||
|
// Every timeout set since the last cleanupPopup() that has neither fired nor
|
||||||
|
// been cleared. cleanupPopup() clears them all.
|
||||||
|
const pendingTimeouts = new Set();
|
||||||
|
|
||||||
const POPUP_HTML = fs.readFileSync(
|
const POPUP_HTML = fs.readFileSync(
|
||||||
path.join(__dirname, "..", "..", "src", "popup", "index.html"),
|
path.join(__dirname, "..", "..", "src", "popup", "index.html"),
|
||||||
@@ -342,6 +348,24 @@ async function bootPopup(stored, options) {
|
|||||||
globalThis.clearInterval = (id) => {
|
globalThis.clearInterval = (id) => {
|
||||||
intervals.delete(id);
|
intervals.delete(id);
|
||||||
};
|
};
|
||||||
|
// Timeouts, such as the one that clears a flash message, run for real, but
|
||||||
|
// each is recorded until it fires or is cleared, so cleanupPopup() can
|
||||||
|
// clear the ones still pending. One that fired after the page was removed
|
||||||
|
// would throw "document is not defined" into whatever test the worker runs
|
||||||
|
// by then. jest.useFakeTimers() in a test does not reach them. Put back by
|
||||||
|
// cleanupPopup().
|
||||||
|
globalThis.setTimeout = (fn, ms, ...args) => {
|
||||||
|
const timer = realSetTimeout(() => {
|
||||||
|
pendingTimeouts.delete(timer);
|
||||||
|
fn(...args);
|
||||||
|
}, ms);
|
||||||
|
pendingTimeouts.add(timer);
|
||||||
|
return timer;
|
||||||
|
};
|
||||||
|
globalThis.clearTimeout = (timer) => {
|
||||||
|
pendingTimeouts.delete(timer);
|
||||||
|
realClearTimeout(timer);
|
||||||
|
};
|
||||||
|
|
||||||
require("../../src/popup/index");
|
require("../../src/popup/index");
|
||||||
|
|
||||||
@@ -407,6 +431,10 @@ function cleanupPopup() {
|
|||||||
delete globalThis.window;
|
delete globalThis.window;
|
||||||
globalThis.setInterval = realSetInterval;
|
globalThis.setInterval = realSetInterval;
|
||||||
globalThis.clearInterval = realClearInterval;
|
globalThis.clearInterval = realClearInterval;
|
||||||
|
for (const timer of pendingTimeouts) realClearTimeout(timer);
|
||||||
|
pendingTimeouts.clear();
|
||||||
|
globalThis.setTimeout = realSetTimeout;
|
||||||
|
globalThis.clearTimeout = realClearTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
Reference in New Issue
Block a user