/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const { PromiseTestUtils } = ChromeUtils.importESModule( "resource://testing-common/PromiseTestUtils.sys.mjs" ); // Allow rejections related to closing an about:debugging too soon after it has been // just opened in a new tab and loaded. PromiseTestUtils.allowMatchingRejectionsGlobally(/Connection closed/); function waitForDispatch(store, type) { return new Promise(resolve => { store.dispatch({ type: "@@service/waitUntil", predicate: action => action.type === type, run: (dispatch, getState, action) => { resolve(action); }, }); }); } /** * Wait for all client requests to settle, meaning here that no new request has been * dispatched after the provided delay. (NOTE: same test helper used in about:debugging tests) */ async function waitForRequestsToSettle(store, delay = 500) { let hasSettled = false; // After each iteration of this while loop, we check is the timerPromise had the time // to resolve or if we captured a REQUEST_*_SUCCESS action before. while (!hasSettled) { let timer; // This timer will be executed only if no REQUEST_*_SUCCESS action is dispatched // during the delay. We consider that when no request are received for some time, it // means there are no ongoing requests anymore. const timerPromise = new Promise(resolve => { // eslint-disable-next-line mozilla/no-arbitrary-setTimeout timer = setTimeout(() => { hasSettled = true; resolve(); }, delay); }); // Wait either for a REQUEST_*_SUCCESS to be dispatched, or for the timer to resolve. await Promise.race([ waitForDispatch(store, "REQUEST_EXTENSIONS_SUCCESS"), waitForDispatch(store, "REQUEST_TABS_SUCCESS"), waitForDispatch(store, "REQUEST_WORKERS_SUCCESS"), timerPromise, ]); // Clear the timer to avoid setting hasSettled to true accidently unless timerPromise // was the first to resolve. clearTimeout(timer); } } function waitForRequestsSuccess(store) { return Promise.all([ waitForDispatch(store, "REQUEST_EXTENSIONS_SUCCESS"), waitForDispatch(store, "REQUEST_TABS_SUCCESS"), waitForDispatch(store, "REQUEST_WORKERS_SUCCESS"), ]); } add_task(async function testAboutDebugging() { let win = await loadInitialView("extension"); let aboutAddonsTab = gBrowser.selectedTab; let debugAddonsBtn = win.document.querySelector( '#page-options [action="debug-addons"]' ); // Verify the about:debugging is loaded. info(`Check about:debugging loads`); let loaded = BrowserTestUtils.waitForNewTab( gBrowser, "about:debugging#/runtime/this-firefox", true ); debugAddonsBtn.click(); await loaded; let aboutDebuggingTab = gBrowser.selectedTab; const { AboutDebugging } = aboutDebuggingTab.linkedBrowser.contentWindow; // Avoid test failures due to closing the about:debugging tab // while it is still initializing. info("Wait until about:debugging actions are finished"); await waitForRequestsSuccess(AboutDebugging.store); info("Switch back to about:addons"); await BrowserTestUtils.switchTab(gBrowser, aboutAddonsTab); is(gBrowser.selectedTab, aboutAddonsTab, "Back to about:addons"); info("Re-open about:debugging"); let switched = TestUtils.waitForCondition( () => gBrowser.selectedTab == aboutDebuggingTab ); debugAddonsBtn.click(); await switched; await waitForRequestsToSettle(AboutDebugging.store); info("Force about:debugging to a different hash URL"); aboutDebuggingTab.linkedBrowser.contentWindow.location.hash = "/setup"; info("Switch back to about:addons again"); await BrowserTestUtils.switchTab(gBrowser, aboutAddonsTab); is(gBrowser.selectedTab, aboutAddonsTab, "Back to about:addons"); info("Re-open about:debugging a second time"); switched = TestUtils.waitForCondition( () => gBrowser.selectedTab == aboutDebuggingTab ); debugAddonsBtn.click(); await switched; info("Wait until any new about:debugging request did settle"); // Avoid test failures due to closing the about:debugging tab // while it is still initializing. await waitForRequestsToSettle(AboutDebugging.store); info("Remove the about:debugging tab"); BrowserTestUtils.removeTab(aboutDebuggingTab); await closeView(win); });