Bug 1766485 - [devtools] Consider server side target switching always enabled for tab toolboxes. r=devtools-reviewers,nchevobbe

This removes the devtools.target-switching.server.enabled preference,
which was only having an impact on tab debugging.
Toolboxes other than tabs aren't yet using "server side target switching",
which will probably happen once we enable EFT in these and
we would probably not use a preference for enabling this.

This remove all assertions in tests covering client side target switching.
And it removed a couple of tests that became irrelevant.

Differential Revision: https://phabricator.services.mozilla.com/D166921
This commit is contained in:
Alexandre Poirot 2023-01-30 12:49:54 +00:00
parent cd7bfe4eb2
commit 8e9b448440
29 changed files with 178 additions and 1033 deletions

View File

@ -45,9 +45,6 @@ async function testSourcesOnNavigation() {
async function testDebuggerPauseStateOnNavigation() {
info("Test the debugger pause state when navigating using the BFCache");
if (Services.appinfo.sessionHistoryInParent) {
enableTargetSwitching();
}
const dbg = await initDebugger("doc-bfcache1.html");
await addBreakpoint(dbg, "doc-bfcache1.html", 4);

View File

@ -8,10 +8,7 @@
add_task(async function() {
// This test fails with server side target switching disabled
if (
(!isFissionEnabled() || !isServerTargetSwitchingEnabled()) &&
!isEveryFrameTargetEnabled()
) {
if (!isFissionEnabled() && !isEveryFrameTargetEnabled()) {
return;
}

View File

@ -18,10 +18,6 @@ const PREFERENCES = [
"will switch between two distinct processes. And if an iframe is " +
"hosted from another domain, it will run in another process",
],
[
"devtools.target-switching.server.enabled",
"Enable experimental server side target switching",
],
[
"devtools.every-frame-target.enabled",
"When enabled, targets will be created for all iframes, no matter if " +

View File

@ -84,7 +84,6 @@ prefs =
[browser_commands_from_url.js]
[browser_target_cached-front.js]
[browser_target_cached-resource.js]
[browser_target_events.js]
[browser_target_loading.js]
[browser_target_parents.js]
skip-if = tsan # bug 1807041

View File

@ -47,26 +47,15 @@ add_task(async function() {
const newTarget = toolbox.target;
const serverSideTargetSwitchingEnabled = Services.prefs.getBoolPref(
"devtools.target-switching.server.enabled"
is(
comTabTarget.actorID,
null,
"With Fission or server side target switching, example.com target front is destroyed"
);
ok(
comTabTarget != newTarget,
"With Fission or server side target switching, a new target was created for example.org"
);
if (isFissionEnabled() || serverSideTargetSwitchingEnabled) {
is(
comTabTarget.actorID,
null,
"With Fission or server side target switching, example.com target front is destroyed"
);
ok(
comTabTarget != newTarget,
"With Fission or server side target switching, a new target was created for example.org"
);
} else {
is(
comTabTarget,
newTarget,
"Without Fission, nor server side targets, the example.com target is reused"
);
}
const onDescriptorDestroyed = tabDescriptor.once("descriptor-destroyed");

View File

@ -1,45 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
add_task(async function() {
// Navigation events (navigate/will-navigate) on the target no longer fire with server targets.
// And as bfcache in parent introduce server target, they are also missing in this case.
// We should probably drop this test once we stop supporting client side targets (bug 1721852).
await pushPref("devtools.target-switching.server.enabled", false);
// Disable bfcache for Fission for now.
// If Fission is disabled, the pref is no-op.
await SpecialPowers.pushPrefEnv({
set: [["fission.bfcacheInParent", false]],
});
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
const commands = await CommandsFactory.forTab(gBrowser.selectedTab);
is(
commands.descriptorFront.localTab,
gBrowser.selectedTab,
"Target linked to the right tab."
);
await commands.targetCommand.startListening();
const { targetFront } = commands.targetCommand;
const willNavigate = once(targetFront, "will-navigate");
const navigate = once(targetFront, "navigate");
SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
content.location = "data:text/html,<meta charset='utf8'/>test navigation";
});
await willNavigate;
ok(true, "will-navigate event received");
await navigate;
ok(true, "navigate event received");
const onTargetDestroyed = once(targetFront, "target-destroyed");
gBrowser.removeCurrentTab();
await onTargetDestroyed;
ok(true, "target destroyed received");
await commands.destroy();
});

View File

@ -8,16 +8,6 @@ const EXAMPLE_ORG_URI =
"https://example.org/document-builder.sjs?html=<div id=org>org";
add_task(async function() {
info("Test with server side target switching ENABLED");
await pushPref("devtools.target-switching.server.enabled", true);
await testCase();
info("Test with server side target switching DISABLED");
await pushPref("devtools.target-switching.server.enabled", false);
await testCase();
});
async function testCase() {
const tab = await addTab(EXAMPLE_COM_URI);
const toolbox = await openToolboxForTab(tab, "inspector");
@ -58,7 +48,7 @@ async function testCase() {
aboutRobotsAfterNavigation,
"Found node for the about:robots page after navigation"
);
}
});
async function getNodeBySelector(toolbox, selector) {
const inspector = await toolbox.selectTool("inspector");

View File

@ -28,8 +28,6 @@ const {
DescriptorMixin,
} = require("resource://devtools/client/fronts/descriptors/descriptor-mixin.js");
const SERVER_TARGET_SWITCHING_ENABLED_PREF =
"devtools.target-switching.server.enabled";
const POPUP_DEBUG_PREF = "devtools.popups.debug";
/**
@ -143,12 +141,7 @@ class TabDescriptorFront extends DescriptorMixin(
}
isServerTargetSwitchingEnabled() {
const isEnabled = Services.prefs.getBoolPref(
SERVER_TARGET_SWITCHING_ENABLED_PREF,
false
);
const enabled = isEnabled && !this._disableTargetSwitching;
return enabled;
return !this._disableTargetSwitching;
}
/**

View File

@ -111,22 +111,11 @@ add_task(async function() {
});
function getOnInspectorReadyAfterNavigation(inspector) {
const promises = [inspector.once("reloaded")];
if (
isFissionEnabled() ||
isServerTargetSwitchingEnabled() ||
isEveryFrameTargetEnabled()
) {
return Promise.all([
inspector.once("reloaded"),
// the inspector is initializing the accessibility front in onTargetAvailable, so we
// need to wait for the target to be processed, otherwise we may end up with pending
// promises failures.
promises.push(
inspector.toolbox.commands.targetCommand.once(
"processed-available-target"
)
);
}
return Promise.all(promises);
inspector.toolbox.commands.targetCommand.once("processed-available-target"),
]);
}

View File

@ -198,10 +198,6 @@ tags = addons
[browser_dbg_listtabs-01.js]
[browser_dbg_listtabs-02.js]
skip-if = true # Never worked for remote frames, needs a mock DevToolsServerConnection
[browser_dbg_listtabs-03.js]
skip-if = debug
[browser_dbg_multiple-windows.js]
[browser_dbg_navigation.js]
skip-if = debug
[browser_dbg_target-scoped-actor-01.js]
[browser_dbg_target-scoped-actor-02.js]

View File

@ -1,155 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Assert the lifecycle of tab descriptors between listTabs and getTab
*/
var {
DevToolsServer,
} = require("resource://devtools/server/devtools-server.js");
var {
DevToolsClient,
} = require("resource://devtools/client/devtools-client.js");
const TAB1_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
add_task(async function test() {
// This test assert RDP APIs which were only meaningful when doing client side targets.
// Now that targets are all created by the Watcher, it is no longer meaningful to cover this.
// We should probably remove this test in bug 1721852.
await pushPref("devtools.target-switching.server.enabled", false);
DevToolsServer.init();
DevToolsServer.registerAllActors();
const transport = DevToolsServer.connectPipe();
const client = new DevToolsClient(transport);
const [type] = await client.connect();
is(type, "browser", "Root actor should identify itself as a browser.");
const tab1 = await addTab(TAB1_URL);
await assertListTabs(tab1, client.mainRoot);
const tab2 = await addTab(TAB1_URL);
// To run last as it will close the client
await assertGetTab(client, client.mainRoot, tab2);
});
async function assertListTabs(tab, rootFront) {
const tabDescriptors = await rootFront.listTabs();
is(tabDescriptors.length, 2, "Should be two tabs");
const tabDescriptor = tabDescriptors.find(d => d.url == TAB1_URL);
ok(tabDescriptor, "Should have a descriptor actor for the tab");
ok(
!tabDescriptor.isLocalTab,
"listTabs's tab descriptor aren't considered as local tabs"
);
const tabTarget = await tabDescriptor.getTarget();
ok(isTargetAttached(tabTarget), "The tab target should be attached");
info("Detach the tab target");
const onTargetDestroyed = tabTarget.once("target-destroyed");
await tabTarget.detach();
info("Wait for target destruction");
await onTargetDestroyed;
// When the target is detached and destroyed,
// the descriptor stays alive, because the tab is still opened.
// As we support top level target switching, the descriptor can be kept alive
// when the target is destroyed.
ok(
!tabDescriptor.isDestroyed(),
"The tab descriptor isn't destroyed on target detach"
);
info("Close the descriptor's tab");
const onDescriptorDestroyed = tabDescriptor.once("descriptor-destroyed");
await removeTab(tab);
info("Wait for descriptor destruction");
await onDescriptorDestroyed;
ok(
tabTarget.isDestroyed(),
"The tab target should be destroyed after closing the tab"
);
ok(
tabDescriptor.isDestroyed(),
"The tab descriptor is also always destroyed after tab closing"
);
// Compared to getTab, the client should be kept alive.
// Do another request to assert that.
await rootFront.listTabs();
}
async function assertGetTab(client, rootFront, tab) {
const tabDescriptor = await rootFront.getTab({ tab });
ok(tabDescriptor, "Should have a descriptor actor for the tab");
ok(
tabDescriptor.isLocalTab,
"getTab's tab descriptor are considered as local tabs, but only when a tab argument is given"
);
// Also assert that getTab only return local tabs when passing the "tab" argument.
// Other arguments will return a non-local tab, having same behavior as listTabs's descriptors
// Test on another tab, otherwise we would return the same descriptor as the one retrieved
// from assertGetTab.
const tab2 = await addTab("data:text/html,second tab");
const tabDescriptor2 = await rootFront.getTab({
browserId: tab2.linkedBrowser.browserId,
});
ok(
!tabDescriptor2.isLocalTab,
"getTab's tab descriptor aren't considered as local tabs when we pass an browserId"
);
await removeTab(tab2);
const tabTarget = await tabDescriptor.getTarget();
ok(isTargetAttached(tabTarget), "The tab target should be attached");
info("Detach the tab target");
const onTargetDestroyed = tabTarget.once("target-destroyed");
await tabTarget.detach();
info("Wait for target destruction");
await onTargetDestroyed;
// When the target is detached and destroyed,
// the descriptor stays alive, because the tab is still opened.
// And compared to listTabs, getTab's descriptor are considered local tabs.
// As we support top level target switching, the descriptor can be kept alive
// when the target is destroyed.
ok(
!tabDescriptor.isDestroyed(),
"The tab descriptor isn't destroyed on target detach"
);
info("Close the descriptor's tab");
const onDescriptorDestroyed = tabDescriptor.once("descriptor-destroyed");
await removeTab(tab);
info("Wait for descriptor destruction");
await onDescriptorDestroyed;
ok(
tabTarget.isDestroyed(),
"The tab target should be destroyed after closing the tab"
);
ok(
tabDescriptor.isDestroyed(),
"The tab descriptor is also always destroyed after tab closing"
);
await client.close();
}
function isTargetAttached(targetFront) {
return !!targetFront?.targetForm?.threadActor;
}

View File

@ -1,61 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Check tab attach/navigation.
*/
const TAB1_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
const TAB2_FILE = "doc_empty-tab-02.html";
const TAB2_URL = EXAMPLE_URL + TAB2_FILE;
add_task(async () => {
// Navigation events (navigate/will-navigate/tabNavigated) on the target no longer fire with server targets.
// We should probably drop this test once we stop supporting client side targets (bug 1721852).
await pushPref("devtools.target-switching.server.enabled", false);
const tab = await addTab(TAB1_URL);
const target = await createAndAttachTargetForTab(tab);
await testNavigate(target);
await testTargetDestroyed(target);
});
function testNavigate(target) {
return new Promise(resolve => {
let gotStartPacket = false;
target.on("tabNavigated", function onTabNavigated(packet) {
is(
packet.url.split("/").pop(),
TAB2_FILE,
"Got a tab navigation notification."
);
info(JSON.stringify(packet));
if (packet.state == "start") {
ok(true, "Tab started to navigate.");
gotStartPacket = true;
} else if (gotStartPacket) {
ok(true, "Tab finished navigating.");
target.off("tabNavigated", onTabNavigated);
resolve();
}
});
BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, TAB2_URL);
});
}
async function testTargetDestroyed(target) {
// We can't listen for tabDetached at it is received by Target first
// and target is destroyed
const onDetached = target.once("target-destroyed");
removeTab(gBrowser.selectedTab);
await onDetached;
ok(true, "Got a tab detach notification.");
}

View File

@ -135,8 +135,6 @@ const URL_ROOT_MOCHI_8888 = CHROME_URL_ROOT.replace(
"http://mochi.test:8888/"
);
const TARGET_SWITCHING_PREF = "devtools.target-switching.server.enabled";
try {
if (isMochitest) {
Services.scriptloader.loadSubScript(
@ -919,17 +917,6 @@ function isFissionEnabled() {
return SpecialPowers.useRemoteSubframes;
}
function isServerTargetSwitchingEnabled() {
return Services.prefs.getBoolPref(TARGET_SWITCHING_PREF);
}
/**
* Enables server target switching
*/
async function enableTargetSwitching() {
await pushPref(TARGET_SWITCHING_PREF, true);
}
function isEveryFrameTargetEnabled() {
return Services.prefs.getBoolPref(
"devtools.every-frame-target.enabled",

View File

@ -5,18 +5,7 @@
/* import-globals-from head.js */
"use strict";
// test without target switching
add_task(async function() {
await testNavigation();
});
// test with target switching enabled
add_task(async function() {
enableTargetSwitching();
await testNavigation();
});
async function testNavigation() {
// Bug 1617611: Fix all the tests broken by "cookies SameSite=lax by default"
await SpecialPowers.pushPrefEnv({
set: [["network.cookie.sameSite.laxByDefault", false]],
@ -148,4 +137,4 @@ async function testNavigation() {
);
SpecialPowers.clearUserPref("network.cookie.sameSite.laxByDefault");
}
});

View File

@ -8,18 +8,7 @@
requestLongerTimeout(3);
// test without target switching
add_task(async function() {
await testNavigation(true);
});
// test with target switching enabled
add_task(async function() {
enableTargetSwitching();
await testNavigation();
});
async function testNavigation(shallCleanup = false) {
const URL1 = URL_ROOT_COM_SSL + "storage-indexeddb-simple.html";
const URL2 = URL_ROOT_NET_SSL + "storage-indexeddb-simple-alt.html";
@ -75,12 +64,7 @@ async function testNavigation(shallCleanup = false) {
"Indexed DB",
"indexedDB item is properly displayed"
);
// clean up if needed
if (shallCleanup) {
await clearStorage();
}
}
});
async function clearStorage() {
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() {

View File

@ -6,18 +6,7 @@
"use strict";
// test without target switching
add_task(async function() {
await testNavigation();
});
// test with target switching enabled
add_task(async function() {
enableTargetSwitching();
await testNavigation();
});
async function testNavigation() {
const URL1 = buildURLWithContent(
"example.com",
`<h1>example.com</h1>` +
@ -73,4 +62,4 @@ async function testNavigation() {
"Local Storage",
"localStorage item is properly displayed"
);
}
});

View File

@ -6,18 +6,7 @@
"use strict";
// test without target switching
add_task(async function() {
await testNavigation();
});
// test with target switching enabled
add_task(async function() {
enableTargetSwitching();
await testNavigation();
});
async function testNavigation() {
const URL1 = buildURLWithContent(
"example.com",
`<h1>example.com</h1>` +
@ -70,4 +59,4 @@ async function testNavigation() {
"Session Storage",
"sessionStorage item is properly displayed"
);
}
});

View File

@ -25,11 +25,6 @@ registerCleanupFunction(function() {
});
add_task(async function() {
// Run with server side targets in order to avoid the restart
// of console and error resource listeners during a client side target switching.
// This leads to unexpected order between console and error messages
await pushPref("devtools.target-switching.server.enabled", true);
const hud = await openNewTabAndConsole(TEST_URI);
info("Test TLS warnings");

View File

@ -39,10 +39,10 @@ add_task(async function() {
// Navigation clears messages. Wait for that clear to happen before
// continuing the test or it might destroy messages we wait later on (Bug
// 1270234).
const promises = [hud.ui.once("messages-cleared")];
if (isFissionEnabled() || isServerTargetSwitchingEnabled()) {
promises.push(hud.commands.targetCommand.once("switched-target"));
}
const promises = [
hud.ui.once("messages-cleared"),
hud.commands.targetCommand.once("switched-target"),
];
gBrowser.goBack();

View File

@ -239,7 +239,7 @@ const windowGlobalTargetPrototype = {
* If true, the target actor will only inspect the current WindowGlobal (and its children windows).
* But won't inspect next document loaded in the same BrowsingContext.
* The actor will behave more like a WindowGlobalTarget rather than a BrowsingContextTarget.
* Since we enabled devtools.target-switching.server.enabled by default, this is always true.
* This is always true for Tab debugging, but not yet for parent process/web extension.
* - isTopLevelTarget Boolean
* Should be set to true for all top-level targets. A top level target
* is the topmost target of a DevTools "session". For instance for a local

View File

@ -355,8 +355,6 @@ export class DevToolsFrameChild extends JSWindowActorChild {
// Targets created from the server side, via Watcher actor and DevToolsFrame JSWindow
// actor pair are following WindowGlobal lifecycle. i.e. will be destroyed on any
// type of navigation/reload.
// Note that if devtools.target-switching.server.enabled is false, the top level target
// won't be created via the codepath. Except if we have a bfcache-in-parent navigation.
followWindowGlobalLifeCycle: true,
isTopLevelTarget,
ignoreSubFrames: isEveryFrameTargetEnabled,

View File

@ -164,26 +164,11 @@ add_task(async function() {
is(index, 2, "Current index is correct");
await a11yWalker.hideTabbingOrder();
// If server targets are enable, reloads will spawn a new toplevel target,
// so that we can no longer expect an event on previous target's front.
// Instead the panel should emit the 'reloaded' event.
if (isServerTargetSwitchingEnabled()) {
info(
"When targets follow the WindowGlobal lifecycle and handle only one document, " +
"only check that the panel refreshes correctly and emit its 'reloaded' event"
);
await reloadBrowser();
} else {
info(
"When targets follow the DocShell lifecycle and handle more than one document, " +
"check that document-ready event fired by walker when top level accessible document is recreated."
);
const reloaded = BrowserTestUtils.browserLoaded(browser);
const documentReady = a11yWalker.once("document-ready");
browser.reload();
await reloaded;
await documentReady;
}
info(
"When targets follow the WindowGlobal lifecycle and handle only one document, " +
"only check that the panel refreshes correctly and emit its 'reloaded' event"
);
await reloadBrowser();
await waitForA11yShutdown(parentAccessibility);
await target.destroy();

View File

@ -45,7 +45,6 @@ support-files =
[test_highlighter_paused_debugger.html]
[test_inspector-changeattrs.html]
[test_inspector-changevalue.html]
[test_inspector-dead-nodes.html]
[test_inspector-display-type.html]
[test_inspector-duplicate-node.html]
[test_inspector_getImageData.html]

View File

@ -1,350 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1121528
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1121528</title>
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript" src="inspector-helpers.js"></script>
<script type="application/javascript">
"use strict";
// TODO: With server side target switching (devtools.target-switching.server.enabled),
// this test is most likely irrelevant.
// APIs that might survive a reload should be moved to commands instead of
// target scoped fronts, because targets no longer survive a reload.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1726597
window.onload = function() {
// For some reason, this test fails more frequently when EFT is enabled.
if (Services.prefs.getBoolPref("devtools.every-frame-target.enabled")) {
ok(true, "EFT is enabled, don't run the test");
SimpleTest.finish();
return;
}
SimpleTest.waitForExplicitFinish();
runNextTest();
};
let gWalker = null;
let gDoc = null;
let gResourceCommand = null;
let gRootNodeResolve = null;
let gCommands = null;
async function reloadTarget() {
const rootNodePromise = new Promise(r => (gRootNodeResolve = r));
gDoc.defaultView.location.reload();
await rootNodePromise;
gWalker = (await gCommands.targetCommand.targetFront.getFront("inspector")).walker;
}
addAsyncTest(async function() {
const url = document.getElementById("inspectorContent").href;
const { commands, doc } = await attachURL(url);
const target = commands.targetCommand.targetFront;
gDoc = doc;
const inspector = await target.getFront("inspector");
gWalker = inspector.walker;
gResourceCommand = commands.resourceCommand;
gCommands = commands;
info("Start watching for root nodes and wait for the initial root node");
const rootNodePromise = new Promise(r => (gRootNodeResolve = r));
const onAvailable = rootNodeFront => gRootNodeResolve(rootNodeFront);
await gResourceCommand.watchResources([gResourceCommand.TYPES.ROOT_NODE], {
onAvailable,
});
await rootNodePromise;
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.children(nodeFront) before the load completes shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "body");
await reloadTarget();
await gWalker.children(nodeFront);
ok(true, "The call to walker.children() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.nextSibling(nodeFront) before the load completes shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
await reloadTarget();
await gWalker.nextSibling(nodeFront);
ok(true, "The call to walker.nextSibling() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.previousSibling(nodeFront) before the load completes shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
await reloadTarget();
await gWalker.previousSibling(nodeFront);
ok(true, "The call to walker.previousSibling() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.addPseudoClassLock(nodeFront) before the load completes " +
"shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
await reloadTarget();
await gWalker.addPseudoClassLock(nodeFront, ":hover");
ok(true, "The call to walker.addPseudoClassLock() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.removePseudoClassLock(nodeFront) before the load completes " +
"shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
await reloadTarget();
await gWalker.removePseudoClassLock(nodeFront, ":hover");
ok(true, "The call to walker.removePseudoClassLock() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.clearPseudoClassLocks(nodeFront) before the load completes " +
"shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
await reloadTarget();
await gWalker.clearPseudoClassLocks(nodeFront);
ok(true, "The call to walker.clearPseudoClassLocks() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.innerHTML(nodeFront) before the load completes shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
await reloadTarget();
await gWalker.innerHTML(nodeFront);
ok(true, "The call to walker.innerHTML() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.setInnerHTML(nodeFront) before the load completes shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
await reloadTarget();
await gWalker.setInnerHTML(nodeFront, "<span>innerHTML changed</span>");
ok(true, "The call to walker.setInnerHTML() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.outerHTML(nodeFront) before the load completes shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
await reloadTarget();
await gWalker.outerHTML(nodeFront);
ok(true, "The call to walker.outerHTML() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.setOuterHTML(nodeFront) before the load completes shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
await reloadTarget();
await gWalker.setOuterHTML(nodeFront, "<h1><span>innerHTML changed</span></h1>");
ok(true, "The call to walker.setOuterHTML() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.insertAdjacentHTML(nodeFront) before the load completes shouldn't " +
"fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
await reloadTarget();
await gWalker.insertAdjacentHTML(nodeFront, "afterEnd",
"<span>new adjacent HTML</span>");
ok(true, "The call to walker.insertAdjacentHTML() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.removeNode(nodeFront) before the load completes should throw");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
await reloadTarget();
let hasThrown = false;
try {
await gWalker.removeNode(nodeFront);
} catch (e) {
hasThrown = true;
}
ok(hasThrown, "The call to walker.removeNode() threw");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.removeNodes([nodeFront]) before the load completes should throw");
const nodeFront1 = await gWalker.querySelector(gWalker.rootNode, "h1");
const nodeFront2 = await gWalker.querySelector(gWalker.rootNode, "#longstring");
const nodeFront3 = await gWalker.querySelector(gWalker.rootNode, "#shortstring");
await reloadTarget();
let hasThrown = false;
try {
await gWalker.removeNodes([nodeFront1, nodeFront2, nodeFront3]);
} catch (e) {
hasThrown = true;
}
ok(hasThrown, "The call to walker.removeNodes() threw");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.insertBefore(nodeFront, parent, null) before the load completes " +
"shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
const newParentFront = await gWalker.querySelector(gWalker.rootNode, "#longlist");
await reloadTarget();
await gWalker.insertBefore(nodeFront, newParentFront);
ok(true, "The call to walker.insertBefore() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.insertBefore(nodeFront, parent, sibling) before the load completes " +
"shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
const newParentFront = await gWalker.querySelector(gWalker.rootNode, "#longlist");
const siblingFront = await gWalker.querySelector(gWalker.rootNode, "#b");
await reloadTarget();
await gWalker.insertBefore(nodeFront, newParentFront, siblingFront);
ok(true, "The call to walker.insertBefore() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.editTagName(nodeFront) before the load completes shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
await reloadTarget();
await gWalker.editTagName(nodeFront, "h2");
ok(true, "The call to walker.editTagName() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.hideNode(nodeFront) before the load completes shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
await reloadTarget();
await gWalker.hideNode(nodeFront);
ok(true, "The call to walker.hideNode() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.unhideNode(nodeFront) before the load completes shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
await reloadTarget();
await gWalker.unhideNode(nodeFront);
ok(true, "The call to walker.unhideNode() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.releaseNode(nodeFront) before the load completes shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "h1");
await reloadTarget();
await gWalker.releaseNode(nodeFront);
ok(true, "The call to walker.releaseNode() didn't fail");
runNextTest();
});
addAsyncTest(async function() {
info("Getting a nodeFront, reloading the page, and calling " +
"walker.querySelector(nodeFront) before the load completes shouldn't fail");
const nodeFront = await gWalker.querySelector(gWalker.rootNode, "body");
await reloadTarget();
await gWalker.querySelector(nodeFront, "h1");
ok(true, "The call to walker.querySelector() didn't fail");
runNextTest();
});
addTest(function cleanup() {
gWalker = null;
gDoc = null;
gResourceCommand = null;
runNextTest();
});
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=932937">Mozilla Bug 1121528</a>
<a id="inspectorContent" target="_blank" href="inspector-traversal-data.html">Test Document</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -12,10 +12,6 @@ add_task(async function() {
await testIframeNavigation();
await testBfCacheNavigation();
await testDomCompleteWithWindowStop();
// Enable server side target switching for next test
// as the regression it tracks only occurs with server side target switching enabled
await pushPref("devtools.target-switching.server.enabled", true);
await testCrossOriginNavigation();
});

View File

@ -11,9 +11,6 @@ add_task(async function() {
// Disable click hold and double tap zooming as it might interfere with the test
await pushPref("ui.click_hold_context_menus", false);
await pushPref("apz.allow_double_tap_zooming", false);
// We turn server-side target switching on so touch simulation is enabled when navigating
// to a different origin (See Bug 1704029).
await pushPref("devtools.target-switching.server.enabled", true);
const tab = await addTab(TEST_URI);

View File

@ -14,12 +14,6 @@ add_task(async function() {
// This preference helps destroying the content process when we close the tab
await pushPref("dom.ipc.keepProcessesAlive.web", 1);
info("### Test with server side target switching");
await pushPref("devtools.target-switching.server.enabled", true);
await bfcacheTest();
});
async function bfcacheTest() {
info("## Test with bfcache in parent DISABLED");
await pushPref("fission.bfcacheInParent", false);
await testTopLevelNavigations(false);
@ -36,7 +30,7 @@ async function bfcacheTest() {
await testIframeNavigations(true);
await testTopLevelNavigationsOnDocumentWithIframe(true);
}
}
});
async function testTopLevelNavigations(bfcacheInParent) {
info(" # Test TOP LEVEL navigations");
@ -82,24 +76,13 @@ async function testTopLevelNavigations(bfcacheInParent) {
0,
"We get no destruction when calling watchTargets"
);
if (!isServerTargetSwitchingEnabled()) {
ok(
!targets[0].targetForm.followWindowGlobalLifeCycle,
"the first client side target still follows docshell lifecycle, when server target switching isn't enabled"
);
} else {
ok(
targets[0].targetForm.followWindowGlobalLifeCycle,
"the first server side target follows the WindowGlobal lifecycle, when server target switching is enabled"
);
}
ok(
targets[0].targetForm.followWindowGlobalLifeCycle,
"the first server side target follows the WindowGlobal lifecycle, when server target switching is enabled"
);
// Navigate to the same page with query params
info("Load the second page");
let onDomComplete = bfcacheInParent
? null
: (await waitForNextTopLevelDomCompleteResource(commands))
.onDomCompleteResource;
const secondPageUrl = TEST_COM_URL + "?second-load";
const previousBrowsingContextID = gBrowser.selectedBrowser.browsingContext.id;
ok(
@ -129,95 +112,69 @@ async function testTopLevelNavigations(bfcacheInParent) {
);
}
if (bfcacheInParent || isServerTargetSwitchingEnabled()) {
// When server side target switching is enabled, same-origin navigations also spawn a new top level target
await waitFor(
() => targets.length == 2,
"wait for the next top level target"
);
is(
targets[1],
targetCommand.targetFront,
"the second target is the top level one"
);
// As targetFront.url isn't reliable and might be about:blank,
// try to assert that we got the right target via other means.
// outerWindowID should change when navigating to another process,
// while it would stay equal for in-process navigations.
is(
targets[1].outerWindowID,
gBrowser.selectedBrowser.outerWindowID,
"the second target is for the second page"
);
if (!isServerTargetSwitchingEnabled()) {
ok(
!targets[1].targetForm.followWindowGlobalLifeCycle,
"the new client side target still follows docshell lifecycle"
);
} else {
ok(
targets[1].targetForm.followWindowGlobalLifeCycle,
"the new server side target follows the WindowGlobal lifecycle"
);
}
ok(targets[0].isDestroyed(), "the first target is destroyed");
is(destroyedTargets.length, 1, "We get one target being destroyed...");
is(destroyedTargets[0], targets[0], "...and that's the first one");
} else {
info("Wait for 'dom-complete' resource");
await onDomComplete;
}
// Same-origin navigations also spawn a new top level target
await waitFor(
() => targets.length == 2,
"wait for the next top level target"
);
is(
targets[1],
targetCommand.targetFront,
"the second target is the top level one"
);
// As targetFront.url isn't reliable and might be about:blank,
// try to assert that we got the right target via other means.
// outerWindowID should change when navigating to another process,
// while it would stay equal for in-process navigations.
is(
targets[1].outerWindowID,
gBrowser.selectedBrowser.outerWindowID,
"the second target is for the second page"
);
ok(
targets[1].targetForm.followWindowGlobalLifeCycle,
"the new server side target follows the WindowGlobal lifecycle"
);
ok(targets[0].isDestroyed(), "the first target is destroyed");
is(destroyedTargets.length, 1, "We get one target being destroyed...");
is(destroyedTargets[0], targets[0], "...and that's the first one");
// Go back to the first page, this should be a bfcache navigation, and,
// we should get a new target
info("Go back to the first page");
onDomComplete = bfcacheInParent
? null
: (await waitForNextTopLevelDomCompleteResource(commands))
.onDomCompleteResource;
gBrowser.selectedBrowser.goBack();
if (bfcacheInParent || isServerTargetSwitchingEnabled()) {
await waitFor(
() => targets.length == 3,
"wait for the next top level target"
);
is(
targets[2],
targetCommand.targetFront,
"the third target is the top level one"
);
// Here as this is revived from cache, the url should always be correct
is(targets[2].url, TEST_COM_URL, "the third target is for the first url");
ok(
targets[2].targetForm.followWindowGlobalLifeCycle,
"the third target for bfcache navigations is following the WindowGlobal lifecycle"
);
ok(targets[1].isDestroyed(), "the second target is destroyed");
is(
destroyedTargets.length,
2,
"We get one additional target being destroyed..."
);
is(destroyedTargets[1], targets[1], "...and that's the second one");
await waitFor(
() => targets.length == 3,
"wait for the next top level target"
);
is(
targets[2],
targetCommand.targetFront,
"the third target is the top level one"
);
// Here as this is revived from cache, the url should always be correct
is(targets[2].url, TEST_COM_URL, "the third target is for the first url");
ok(
targets[2].targetForm.followWindowGlobalLifeCycle,
"the third target for bfcache navigations is following the WindowGlobal lifecycle"
);
ok(targets[1].isDestroyed(), "the second target is destroyed");
is(
destroyedTargets.length,
2,
"We get one additional target being destroyed..."
);
is(destroyedTargets[1], targets[1], "...and that's the second one");
// Wait for full attach in order to having breaking any pending requests
// when navigating to another page and switching to new process and target.
await waitForAllTargetsToBeAttached(targetCommand);
} else {
info("Wait for 'dom-complete' resource");
await onDomComplete;
}
// Wait for full attach in order to having breaking any pending requests
// when navigating to another page and switching to new process and target.
await waitForAllTargetsToBeAttached(targetCommand);
// Go forward and resurect the second page, this should also be a bfcache navigation, and,
// get a new target.
info("Go forward to the second page");
onDomComplete = bfcacheInParent
? null
: (await waitForNextTopLevelDomCompleteResource(commands))
.onDomCompleteResource;
// When a new target will be created, we need to wait until it's fully processed
// to avoid pending promises.
const onNewTargetProcessed = bfcacheInParent
@ -239,38 +196,33 @@ async function testTopLevelNavigations(bfcacheInParent) {
gBrowser.selectedBrowser.goForward();
if (bfcacheInParent || isServerTargetSwitchingEnabled()) {
await waitFor(
() => targets.length == 4,
"wait for the next top level target"
);
is(
targets[3],
targetCommand.targetFront,
"the 4th target is the top level one"
);
// Same here, as the document is revived from the cache, the url should always be correct
is(targets[3].url, secondPageUrl, "the 4th target is for the second url");
ok(
targets[3].targetForm.followWindowGlobalLifeCycle,
"the 4th target for bfcache navigations is following the WindowGlobal lifecycle"
);
ok(targets[2].isDestroyed(), "the third target is destroyed");
is(
destroyedTargets.length,
3,
"We get one additional target being destroyed..."
);
is(destroyedTargets[2], targets[2], "...and that's the third one");
await waitFor(
() => targets.length == 4,
"wait for the next top level target"
);
is(
targets[3],
targetCommand.targetFront,
"the 4th target is the top level one"
);
// Same here, as the document is revived from the cache, the url should always be correct
is(targets[3].url, secondPageUrl, "the 4th target is for the second url");
ok(
targets[3].targetForm.followWindowGlobalLifeCycle,
"the 4th target for bfcache navigations is following the WindowGlobal lifecycle"
);
ok(targets[2].isDestroyed(), "the third target is destroyed");
is(
destroyedTargets.length,
3,
"We get one additional target being destroyed..."
);
is(destroyedTargets[2], targets[2], "...and that's the third one");
// Wait for full attach in order to having breaking any pending requests
// when navigating to another page and switching to new process and target.
await waitForAllTargetsToBeAttached(targetCommand);
await onNewTargetProcessed;
} else {
info("Wait for 'dom-complete' resource");
await onDomComplete;
}
// Wait for full attach in order to having breaking any pending requests
// when navigating to another page and switching to new process and target.
await waitForAllTargetsToBeAttached(targetCommand);
await onNewTargetProcessed;
await waitForAllTargetsToBeAttached(targetCommand);
@ -358,10 +310,6 @@ async function testTopLevelNavigationsOnDocumentWithIframe(bfcacheInParent) {
info("Navigate to a new page");
let targetCountBeforeNavigation = targets.length;
let onDomComplete = bfcacheInParent
? null
: (await waitForNextTopLevelDomCompleteResource(commands))
.onDomCompleteResource;
const secondPageUrl = `https://example.com/document-builder.sjs?html=second`;
const onLoaded = BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser,
@ -371,87 +319,73 @@ async function testTopLevelNavigationsOnDocumentWithIframe(bfcacheInParent) {
BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, secondPageUrl);
await onLoaded;
if (bfcacheInParent || isServerTargetSwitchingEnabled()) {
// When server side target switching is enabled, same-origin navigations also spawn a new top level target
await waitFor(
() => targets.length == targetCountBeforeNavigation + 1,
"wait for the next top level target"
);
is(
targets.at(-1),
targetCommand.targetFront,
"the new target is the top level one"
);
// Same-origin navigations also spawn a new top level target
await waitFor(
() => targets.length == targetCountBeforeNavigation + 1,
"wait for the next top level target"
);
is(
targets.at(-1),
targetCommand.targetFront,
"the new target is the top level one"
);
ok(targets[0].isDestroyed(), "the first target is destroyed");
if (isEveryFrameTargetEnabled()) {
ok(targets[1].isDestroyed(), "the second target is destroyed");
is(destroyedTargets.length, 2, "The two targets were destroyed");
} else {
is(destroyedTargets.length, 1, "Only one target was destroyed");
}
ok(targets[0].isDestroyed(), "the first target is destroyed");
if (isEveryFrameTargetEnabled()) {
ok(targets[1].isDestroyed(), "the second target is destroyed");
is(destroyedTargets.length, 2, "The two targets were destroyed");
} else {
info("Wait for 'dom-complete' resource");
await onDomComplete;
is(destroyedTargets.length, 1, "Only one target was destroyed");
}
// Go back to the first page, this should be a bfcache navigation, and,
// we should get a new target (or 2 if EFT is enabled)
targetCountBeforeNavigation = targets.length;
info("Go back to the first page");
onDomComplete = bfcacheInParent
? null
: (await waitForNextTopLevelDomCompleteResource(commands))
.onDomCompleteResource;
gBrowser.selectedBrowser.goBack();
if (bfcacheInParent || isServerTargetSwitchingEnabled()) {
await waitFor(
() =>
targets.length ===
targetCountBeforeNavigation + (isEveryFrameTargetEnabled() ? 2 : 1),
"wait for the next top level target"
);
await waitFor(
() =>
targets.length ===
targetCountBeforeNavigation + (isEveryFrameTargetEnabled() ? 2 : 1),
"wait for the next top level target"
);
if (isEveryFrameTargetEnabled()) {
await waitFor(() => targets.at(-2).url && targets.at(-1).url);
is(
getLocationIdParam(targets.at(-2).url),
"top",
"the first new target is for the top document…"
);
is(
getLocationIdParam(targets.at(-1).url),
"iframe",
"…and the second one is for the iframe"
);
} else {
is(
getLocationIdParam(targets.at(-1).url),
"top",
"the new target is for the first url"
);
}
ok(
targets[targetCountBeforeNavigation - 1].isDestroyed(),
"the target for the second page is destroyed"
if (isEveryFrameTargetEnabled()) {
await waitFor(() => targets.at(-2).url && targets.at(-1).url);
is(
getLocationIdParam(targets.at(-2).url),
"top",
"the first new target is for the top document…"
);
is(
destroyedTargets.length,
targetCountBeforeNavigation,
"We get one additional target being destroyed…"
);
is(
destroyedTargets.at(-1),
targets[targetCountBeforeNavigation - 1],
"…and that's the second page one"
getLocationIdParam(targets.at(-1).url),
"iframe",
"…and the second one is for the iframe"
);
} else {
info("Wait for 'dom-complete' resource");
await onDomComplete;
is(
getLocationIdParam(targets.at(-1).url),
"top",
"the new target is for the first url"
);
}
ok(
targets[targetCountBeforeNavigation - 1].isDestroyed(),
"the target for the second page is destroyed"
);
is(
destroyedTargets.length,
targetCountBeforeNavigation,
"We get one additional target being destroyed…"
);
is(
destroyedTargets.at(-1),
targets[targetCountBeforeNavigation - 1],
"…and that's the second page one"
);
await waitForAllTargetsToBeAttached(targetCommand);
targetCommand.unwatchTargets({

View File

@ -83,10 +83,8 @@ async function testNavigationToParentProcessDocument() {
// in our expected listener.
const onSwitchedTarget1 = targetCommand.once("switched-target");
await targetCommand.startListening();
if (isServerTargetSwitchingEnabled()) {
info("wait for first top level target");
await onSwitchedTarget1;
}
info("wait for first top level target");
await onSwitchedTarget1;
const firstTarget = targetCommand.targetFront;
is(firstTarget.url, firstLocation, "first target url is correct");
@ -154,10 +152,8 @@ async function testNavigationToAboutBlankDocument() {
// in our expected listener.
const onSwitchedTarget1 = targetCommand.once("switched-target");
await targetCommand.startListening();
if (isServerTargetSwitchingEnabled()) {
info("wait for first top level target");
await onSwitchedTarget1;
}
info("wait for first top level target");
await onSwitchedTarget1;
const firstTarget = targetCommand.targetFront;
is(firstTarget.url, firstLocation, "first target url is correct");
@ -169,28 +165,18 @@ async function testNavigationToAboutBlankDocument() {
await BrowserTestUtils.loadURIString(browser, secondLocation);
await onLoaded;
if (isServerTargetSwitchingEnabled()) {
await onSwitchedTarget;
isnot(targetCommand.targetFront, firstTarget, "got a new target");
await onSwitchedTarget;
isnot(targetCommand.targetFront, firstTarget, "got a new target");
// Check that calling getAllTargets([frame]) return the same target instances
const frames = await targetCommand.getAllTargets([
targetCommand.TYPES.FRAME,
]);
is(frames.length, 1);
is(frames[0].url, secondLocation, "second target url is correct");
is(
frames[0],
targetCommand.targetFront,
"second target is the current top level one"
);
} else {
is(
targetCommand.targetFront,
firstTarget,
"without server target switching, we stay on the same top level target"
);
}
// Check that calling getAllTargets([frame]) return the same target instances
const frames = await targetCommand.getAllTargets([targetCommand.TYPES.FRAME]);
is(frames.length, 1);
is(frames[0].url, secondLocation, "second target url is correct");
is(
frames[0],
targetCommand.targetFront,
"second target is the current top level one"
);
await commands.destroy();
}
@ -503,10 +489,7 @@ async function testTabFrames(mainRoot) {
info("Navigate to another domain and process (if fission is enabled)");
// When a new target will be created, we need to wait until it's fully processed
// to avoid pending promises.
const onNewTargetProcessed =
isFissionEnabled() || isServerTargetSwitchingEnabled()
? targetCommand.once("processed-available-target")
: null;
const onNewTargetProcessed = targetCommand.once("processed-available-target");
const browser = tab.linkedBrowser;
const onLoaded = BrowserTestUtils.browserLoaded(browser);
@ -564,7 +547,7 @@ async function testTabFrames(mainRoot) {
true,
"the target destruction is flagged as target switching"
);
} else if (isServerTargetSwitchingEnabled()) {
} else {
await waitFor(
() => targets.length == 2,
"Wait for all expected targets after navigation"
@ -587,18 +570,6 @@ async function testTabFrames(mainRoot) {
targets[0].targetFront.isDestroyed(),
"but the previous one is destroyed"
);
} else {
is(targets.length, 1, "without fission, we always have only one target");
is(destroyedTargets.length, 0, "no target should be destroyed");
is(
targetCommand.targetFront,
targets[0].targetFront,
"and that unique target is always the same"
);
ok(
!targetCommand.targetFront.isDestroyed(),
"and that target is never destroyed"
);
}
await onNewTargetProcessed;

View File

@ -16,9 +16,6 @@ const TEST_URL =
`<iframe src=${REMOTE_IFRAME_URL_2}></iframe>`;
add_task(async function() {
// Turn on server side targets
await pushPref("devtools.target-switching.server.enabled", true);
// Create a TargetCommand for a given test tab
const tab = await addTab(TEST_URL);
const commands = await CommandsFactory.forTab(tab);