Source code
Revision control
Copy as Markdown
Other Tools
/* Any copyright is dedicated to the Public Domain.
var testScope;
/**
* Module consumers can optionally initialize the module
*
* @param {object} scope
* object with SimpleTest and info properties.
*/
function init(scope) {
testScope = scope;
}
function getFirefoxViewURL() {
return "about:firefoxview";
}
/**
* Make the given window focused and active
*/
async function switchToWindow(win) {
await testScope.SimpleTest.promiseFocus(win);
if (Services.focus.activeWindow !== win) {
testScope.info("switchToWindow, waiting for activate event on the window");
await BrowserTestUtils.waitForEvent(win, "activate");
} else {
testScope.info("switchToWindow, win is already the activeWindow");
}
testScope.info("switchToWindow, done");
}
function assertFirefoxViewTab(win) {
Assert.ok(win.FirefoxViewHandler.tab, "Firefox View tab exists");
Assert.ok(win.FirefoxViewHandler.tab?.hidden, "Firefox View tab is hidden");
Assert.equal(
win.gBrowser.visibleTabs.indexOf(win.FirefoxViewHandler.tab),
-1,
"Firefox View tab is not in the list of visible tabs"
);
}
async function assertFirefoxViewTabSelected(win) {
assertFirefoxViewTab(win);
Assert.ok(
win.FirefoxViewHandler.tab.selected,
"Firefox View tab is selected"
);
await BrowserTestUtils.browserLoaded(
win.FirefoxViewHandler.tab.linkedBrowser
);
}
async function openFirefoxViewTab(win) {
if (!testScope?.SimpleTest) {
throw new Error(
"Must initialize FirefoxViewTestUtils with a test scope which has a SimpleTest property"
);
}
await switchToWindow(win);
if (
!win.CustomizableUI.getPlacementOfWidget(win.FirefoxViewHandler.BUTTON_ID)
) {
enableFirefoxViewButton(win);
}
let fxviewTab = win.FirefoxViewHandler.tab;
let alreadyLoaded =
fxviewTab?.linkedBrowser.currentURI.spec.includes(getFirefoxViewURL()) &&
fxviewTab?.linkedBrowser?.contentDocument?.readyState == "complete";
let enteredPromise = alreadyLoaded
? Promise.resolve()
: TestUtils.topicObserved("firefoxview-entered");
if (!fxviewTab?.selected) {
testScope.info(
"Navigating to about:firefoxview by clicking firefox-view-button"
);
await BrowserTestUtils.synthesizeMouseAtCenter(
"#firefox-view-button",
{},
win.browsingContext
);
await TestUtils.waitForTick();
}
fxviewTab = win.FirefoxViewHandler.tab;
assertFirefoxViewTab(win);
Assert.ok(
win.FirefoxViewHandler.tab.selected,
"Firefox View tab is selected"
);
testScope.info(
"openFirefoxViewTab, waiting for complete readyState, visible and firefoxview-entered"
);
await enteredPromise;
await TestUtils.waitForCondition(() => {
const document = fxviewTab.linkedBrowser.contentDocument;
return (
document.readyState == "complete" && document.visibilityState == "visible"
);
}, "Waiting for the Firefox View tab document to be complete and visible");
testScope.info("openFirefoxViewTab, ready resolved");
return fxviewTab;
}
function closeFirefoxViewTab(win) {
if (win.FirefoxViewHandler.tab) {
win.gBrowser.removeTab(win.FirefoxViewHandler.tab);
}
Assert.ok(
!win.FirefoxViewHandler.tab,
"Reference to Firefox View tab got removed when closing the tab"
);
}
/**
* Run a task with Firefox View open.
*
* @param {object} options
* Options object.
* @param {boolean} [options.openNewWindow]
* Whether to run the task in a new window. If false, the current window will
* be used.
* @param {boolean} [options.resetFlowManager]
* Whether to reset the internal state of TabsSetupFlowManager before running
* the task.
* @param {Window} [options.win]
* The window in which to run the task.
* @param {(MozBrowser) => any} taskFn
* The task to run. It can be asynchronous.
* @returns {any}
* The value returned by the task.
*/
async function withFirefoxView(
{ openNewWindow = false, resetFlowManager = true, win = null },
taskFn
) {
if (!win) {
win = openNewWindow
? await BrowserTestUtils.openNewBrowserWindow()
: Services.wm.getMostRecentBrowserWindow();
}
if (resetFlowManager) {
const { TabsSetupFlowManager } = ChromeUtils.importESModule(
);
// reset internal state so we aren't reacting to whatever state the last invocation left behind
TabsSetupFlowManager.resetInternalState();
}
// Setting this pref allows the test to run as expected with a keyboard on MacOS
await win.SpecialPowers.pushPrefEnv({
set: [["accessibility.tabfocus", 7]],
});
let tab = await openFirefoxViewTab(win);
let originalWindow = tab.documentGlobal;
let result = await taskFn(tab.linkedBrowser);
let finalWindow = tab.documentGlobal;
if (originalWindow == finalWindow && !tab.closing && tab.linkedBrowser) {
// taskFn may resolve within a tick after opening a new tab.
// We shouldn't remove the newly opened tab in the same tick.
// Wait for the next tick here.
await TestUtils.waitForTick();
BrowserTestUtils.removeTab(tab);
} else {
Services.console.logStringMessage(
"withFirefoxView: Tab was already closed before " +
"removeTab would have been called"
);
}
await win.SpecialPowers.popPrefEnv();
if (openNewWindow) {
await BrowserTestUtils.closeWindow(win);
}
return result;
}
function isFirefoxViewTabSelectedInWindow(win) {
return win.gBrowser.selectedBrowser.currentURI.spec == getFirefoxViewURL();
}
/**
* Adds the Firefox View button to the tabstrip. It will be removed after the
* test ends.
*/
function enableFirefoxViewButton({ CustomizableUI, FirefoxViewHandler }) {
CustomizableUI.addWidgetToArea(
FirefoxViewHandler.BUTTON_ID,
CustomizableUI.AREA_TABSTRIP,
CustomizableUI.getPlacementOfWidget("tabbrowser-tabs").position
);
testScope.registerCleanupFunction(() => {
CustomizableUI.removeWidgetFromArea(FirefoxViewHandler.BUTTON_ID);
});
}
export {
init,
switchToWindow,
withFirefoxView,
assertFirefoxViewTab,
assertFirefoxViewTabSelected,
openFirefoxViewTab,
closeFirefoxViewTab,
isFirefoxViewTabSelectedInWindow,
getFirefoxViewURL,
enableFirefoxViewButton,
};