Backed out 8 changesets (bug 1485660) for damp failures on front.hasRequests. CLOSED TREE

Backed out changeset 7a2f29bbe2a8 (bug 1485660)
Backed out changeset 26e82fa62444 (bug 1485660)
Backed out changeset 9bb2f56f219d (bug 1485660)
Backed out changeset 40a3c2dd1b38 (bug 1485660)
Backed out changeset cfb160882db9 (bug 1485660)
Backed out changeset 3642f2d66777 (bug 1485660)
Backed out changeset 9026679753b2 (bug 1485660)
Backed out changeset dccca441b980 (bug 1485660)
This commit is contained in:
Brindusan Cristian 2018-10-11 22:33:35 +03:00
parent a58b2b1762
commit c328bc1cdf
42 changed files with 399 additions and 386 deletions

View File

@ -91,17 +91,7 @@ add_task(async function testWebExtensionsToolboxSwitchToPopup() {
/* eslint-disable no-undef */
let jsterm;
const popupFramePromise = new Promise(resolve => {
const listener = data => {
if (data.frames.some(({url}) => url && url.endsWith("popup.html"))) {
toolbox.target.off("frame-update", listener);
resolve();
}
};
toolbox.target.on("frame-update", listener);
});
const waitForFrameListUpdate = toolbox.target.once("frame-update");
let popupFramePromise;
toolbox.selectTool("webconsole")
.then(async (console) => {
@ -121,6 +111,18 @@ add_task(async function testWebExtensionsToolboxSwitchToPopup() {
await clickNoAutoHideMenu();
dump(`Clicked the menu button\n`);
popupFramePromise = new Promise(resolve => {
const listener = data => {
if (data.frames.some(({url}) => url && url.endsWith("popup.html"))) {
toolbox.target.off("frame-update", listener);
resolve();
}
};
toolbox.target.on("frame-update", listener);
});
const waitForFrameListUpdate = toolbox.target.once("frame-update");
jsterm = console.hud.jsterm;
jsterm.execute("myWebExtensionShowPopup()");

View File

@ -408,6 +408,6 @@ function reload(target, waitForTargetEvent = "navigate") {
* @param {String} waitForTargetEvent Event to wait for after reload.
*/
function navigate(target, url, waitForTargetEvent = "navigate") {
executeSoon(() => target.activeTab.navigateTo({ url }));
executeSoon(() => target.activeTab.navigateTo(url));
return once(target, waitForTargetEvent);
}

View File

@ -43,7 +43,8 @@ window.Application = {
return toolbox.selectTool(toolId);
}
};
this.toolbox.target.activeTab.on("workerListChanged", this.updateWorkers);
this.client.addListener("workerListChanged", this.updateWorkers);
this.client.addListener("serviceWorkerRegistrationListChanged", this.updateWorkers);
this.client.addListener("registration-changed", this.updateWorkers);
this.client.addListener("processListChanged", this.updateWorkers);
@ -88,7 +89,7 @@ window.Application = {
},
destroy() {
this.toolbox.target.activeTab.off("workerListChanged", this.updateWorkers);
this.client.removeListener("workerListChanged", this.updateWorkers);
this.client.removeListener("serviceWorkerRegistrationListChanged",
this.updateWorkers);
this.client.removeListener("registration-changed", this.updateWorkers);

View File

@ -41,7 +41,7 @@ function getWorkerContainers(doc) {
}
function navigate(target, url, waitForTargetEvent = "navigate") {
executeSoon(() => target.activeTab.navigateTo({ url }));
executeSoon(() => target.activeTab.navigateTo(url));
return once(target, waitForTargetEvent);
}

View File

@ -107,7 +107,7 @@ function navigateInHistory(aTarget, aDirection, aWaitForTargetEvent = "navigate"
}
function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") {
executeSoon(() => aTarget.activeTab.navigateTo({ url: aUrl }));
executeSoon(() => aTarget.activeTab.navigateTo(aUrl));
return once(aTarget, aWaitForTargetEvent);
}

View File

@ -478,22 +478,11 @@ Workers.prototype = {
}
this._updateWorkerList();
// `_tabClient` can be BrowsingContextTargetFront (protocol.js front) or
// WorkerClient/DebuggerClient (old fashion client)
if (typeof(this._tabClient.on) == "function") {
this._tabClient.on("workerListChanged", this._onWorkerListChanged);
} else {
this._tabClient.addListener("workerListChanged", this._onWorkerListChanged);
}
this._tabClient.addListener("workerListChanged", this._onWorkerListChanged);
},
disconnect: function () {
if (typeof(this._tabClient.on) == "function") {
this._tabClient.off("workerListChanged", this._onWorkerListChanged);
} else {
this._tabClient.removeListener("workerListChanged", this._onWorkerListChanged);
}
this._tabClient.removeListener("workerListChanged", this._onWorkerListChanged);
},
_updateWorkerList: function () {

View File

@ -247,7 +247,7 @@ function debuggeeCommand(script) {
}
function navigate(url) {
return tabTarget.activeTab.navigateTo({ url });
return tabTarget.activeTab.navigateTo(url);
}
function reload() {
@ -455,4 +455,4 @@ const clientCommands = {
setSkipPausing
};
exports.setupCommands = setupCommands;
exports.clientCommands = clientCommands;
exports.clientCommands = clientCommands;

View File

@ -41,13 +41,7 @@ function setupEvents(dependencies) {
});
if (threadClient._parent) {
// Parent may be BrowsingContextTargetFront and be protocol.js.
// Or DebuggerClient/WorkerClient and still be old fashion actor.
if (threadClient._parent.on) {
threadClient._parent.on("workerListChanged", workerListChanged);
} else {
threadClient._parent.addListener("workerListChanged", workerListChanged);
}
threadClient._parent.addListener("workerListChanged", workerListChanged);
}
}
}
@ -119,4 +113,4 @@ const clientEvents = {
newSource
};
exports.setupEvents = setupEvents;
exports.clientEvents = clientEvents;
exports.clientEvents = clientEvents;

View File

@ -76,7 +76,7 @@ add_task(async function() {
);
info("Disable HTTP cache for page");
await toolbox.target.activeTab.reconfigure({ options: { cacheDisabled: true } });
await toolbox.target.activeTab.reconfigure({ cacheDisabled: true });
makeChanges();
info("Reload inside debugger with toolbox caching disabled (attempt 1)");
@ -106,7 +106,7 @@ add_task(async function() {
);
info("Enable HTTP cache for page");
await toolbox.target.activeTab.reconfigure({ options: { cacheDisabled: false } });
await toolbox.target.activeTab.reconfigure({ cacheDisabled: false });
makeChanges();
// Even though the HTTP cache is now enabled, Gecko sets the VALIDATE_ALWAYS flag when

View File

@ -180,8 +180,8 @@ function getAddonActorForId(aClient, aAddonId) {
async function attachTargetActorForUrl(aClient, aUrl) {
let grip = await getTargetActorForUrl(aClient, aUrl);
let [ response, front ] = await aClient.attachTarget(grip.actor);
return [grip, response, front];
let [ response ] = await aClient.attachTarget(grip.actor);
return [grip, response];
}
async function attachThreadActorForUrl(aClient, aUrl) {
@ -450,7 +450,7 @@ function ensureThreadClientState(aPanel, aState) {
function reload(aPanel, aUrl) {
let activeTab = aPanel.panelWin.DebuggerController._target.activeTab;
aUrl ? activeTab.navigateTo({ url: aUrl }) : activeTab.reload();
aUrl ? activeTab.navigateTo(aUrl) : activeTab.reload();
}
function navigateActiveTabTo(aPanel, aUrl, aWaitForEventName, aEventRepeat) {
@ -1109,9 +1109,14 @@ function attachWorker(tabClient, worker) {
return tabClient.attachWorker(worker.actor);
}
function waitForWorkerListChanged(targetFront) {
function waitForWorkerListChanged(tabClient) {
info("Waiting for worker list to change.");
return targetFront.once("workerListChanged");
return new Promise(function (resolve) {
tabClient.addListener("workerListChanged", function listener() {
tabClient.removeListener("workerListChanged", listener);
resolve();
});
});
}
function attachThread(workerClient, options) {

View File

@ -194,7 +194,6 @@ const TargetFactory = exports.TargetFactory = {
function TabTarget({ form, client, chrome, tab = null }) {
EventEmitter.decorate(this);
this.destroy = this.destroy.bind(this);
this._onTabNavigated = this._onTabNavigated.bind(this);
this.activeTab = this.activeConsole = null;
this._form = form;
@ -519,12 +518,6 @@ TabTarget.prototype = {
const [response, tabClient] = await this._client.attachTarget(this._form.actor);
this.activeTab = tabClient;
this.threadActor = response.threadActor;
this.activeTab.on("tabNavigated", this._onTabNavigated);
this._onFrameUpdate = packet => {
this.emit("frame-update", packet);
};
this.activeTab.on("frameUpdate", this._onFrameUpdate);
};
// Attach the console actor
@ -556,6 +549,8 @@ TabTarget.prototype = {
this._title = form.title;
}
this._setupRemoteListeners();
// AddonActor and chrome debugging on RootActor don't inherit from
// BrowsingContextTargetActor (i.e. this.isBrowsingContext=false) and don't need
// to be attached.
@ -563,10 +558,6 @@ TabTarget.prototype = {
await attachTarget();
}
// _setupRemoteListeners has to be called after the potential call to `attachTarget`
// as it depends on `activeTab` which is set by this method.
this._setupRemoteListeners();
// But all target actor have a console actor to attach
return attachConsole();
})();
@ -594,95 +585,70 @@ TabTarget.prototype = {
this._tab.removeEventListener("TabRemotenessChange", this);
},
/**
* Event listener for tabNavigated packet sent by activeTab's front.
*/
_onTabNavigated: function(packet) {
const event = Object.create(null);
event.url = packet.url;
event.title = packet.title;
event.nativeConsoleAPI = packet.nativeConsoleAPI;
event.isFrameSwitching = packet.isFrameSwitching;
// Keep the title unmodified when a developer toolbox switches frame
// for a tab (Bug 1261687), but always update the title when the target
// is a WebExtension (where the addon name is always included in the title
// and the url is supposed to be updated every time the selected frame changes).
if (!packet.isFrameSwitching || this.isWebExtension) {
this._url = packet.url;
this._title = packet.title;
}
// Send any stored event payload (DOMWindow or nsIRequest) for backwards
// compatibility with non-remotable tools.
if (packet.state == "start") {
event._navPayload = this._navRequest;
this.emit("will-navigate", event);
this._navRequest = null;
} else {
event._navPayload = this._navWindow;
this.emit("navigate", event);
this._navWindow = null;
}
},
/**
* Setup listeners for remote debugging, updating existing ones as necessary.
*/
_setupRemoteListeners: function() {
this.client.addListener("closed", this.destroy);
// For now, only browsing-context inherited actors are using a front,
// for which events have to be listened on the front itself.
// For other actors (ContentProcessTargetActor and AddonTargetActor), events should
// still be listened directly on the client. This should be ultimately cleaned up to
// only listen from a front by bug 1465635.
if (this.activeTab) {
this.activeTab.on("tabDetached", this.destroy);
this._onTabDetached = (type, packet) => {
// We have to filter message to ensure that this detach is for this tab
if (packet.from == this._form.actor) {
this.destroy();
}
};
this.client.addListener("tabDetached", this._onTabDetached);
// These events should be ultimately listened from the thread client as
// they are coming from it and no longer go through the Target Actor/Front.
this._onSourceUpdated = packet => this.emit("source-updated", packet);
this.activeTab.on("newSource", this._onSourceUpdated);
this.activeTab.on("updatedSource", this._onSourceUpdated);
} else {
this._onTabDetached = (type, packet) => {
// We have to filter message to ensure that this detach is for this tab
if (packet.from == this._form.actor) {
this.destroy();
}
};
this.client.addListener("tabDetached", this._onTabDetached);
this._onTabNavigated = (type, packet) => {
const event = Object.create(null);
event.url = packet.url;
event.title = packet.title;
event.nativeConsoleAPI = packet.nativeConsoleAPI;
event.isFrameSwitching = packet.isFrameSwitching;
this._onSourceUpdated = (type, packet) => this.emit("source-updated", packet);
this.client.addListener("newSource", this._onSourceUpdated);
this.client.addListener("updatedSource", this._onSourceUpdated);
}
// Keep the title unmodified when a developer toolbox switches frame
// for a tab (Bug 1261687), but always update the title when the target
// is a WebExtension (where the addon name is always included in the title
// and the url is supposed to be updated every time the selected frame changes).
if (!packet.isFrameSwitching || this.isWebExtension) {
this._url = packet.url;
this._title = packet.title;
}
// Send any stored event payload (DOMWindow or nsIRequest) for backwards
// compatibility with non-remotable tools.
if (packet.state == "start") {
event._navPayload = this._navRequest;
this.emit("will-navigate", event);
this._navRequest = null;
} else {
event._navPayload = this._navWindow;
this.emit("navigate", event);
this._navWindow = null;
}
};
this.client.addListener("tabNavigated", this._onTabNavigated);
this._onFrameUpdate = (type, packet) => {
this.emit("frame-update", packet);
};
this.client.addListener("frameUpdate", this._onFrameUpdate);
this._onSourceUpdated = (event, packet) => this.emit("source-updated", packet);
this.client.addListener("newSource", this._onSourceUpdated);
this.client.addListener("updatedSource", this._onSourceUpdated);
},
/**
* Teardown listeners for remote debugging.
*/
_teardownRemoteListeners: function() {
// Remove listeners set in _setupRemoteListeners
this.client.removeListener("closed", this.destroy);
if (this.activeTab) {
this.activeTab.off("tabDetached", this.destroy);
this.activeTab.off("newSource", this._onSourceUpdated);
this.activeTab.off("updatedSource", this._onSourceUpdated);
} else {
this.client.removeListener("tabDetached", this._onTabDetached);
this.client.removeListener("newSource", this._onSourceUpdated);
this.client.removeListener("updatedSource", this._onSourceUpdated);
}
// Remove listeners set in attachTarget
if (this.activeTab) {
this.activeTab.off("tabNavigated", this._onTabNavigated);
this.activeTab.off("frameUpdate", this._onFrameUpdate);
}
// Remove listeners set in attachConsole
this.client.removeListener("tabNavigated", this._onTabNavigated);
this.client.removeListener("tabDetached", this._onTabDetached);
this.client.removeListener("frameUpdate", this._onFrameUpdate);
this.client.removeListener("newSource", this._onSourceUpdated);
this.client.removeListener("updatedSource", this._onSourceUpdated);
if (this.activeConsole && this._onInspectObject) {
this.activeConsole.off("inspectObject", this._onInspectObject);
}
@ -775,11 +741,7 @@ TabTarget.prototype = {
// it. We just need to detach from the tab, if already attached.
// |detach| may fail if the connection is already dead, so proceed with
// cleanup directly after this.
try {
await this.activeTab.detach();
} catch (e) {
console.warn(`Error while detaching target: ${e.message}`);
}
this.activeTab.detach();
cleanupAndResolve();
} else {
cleanupAndResolve();
@ -828,7 +790,7 @@ TabTarget.prototype = {
logErrorInPage: function(text, category) {
if (this.activeTab && this.activeTab.traits.logInPage) {
const errorFlag = 0;
this.activeTab.logInPage({ text, category, flags: errorFlag });
this.activeTab.logInPage(text, category, errorFlag);
}
},
@ -843,7 +805,7 @@ TabTarget.prototype = {
logWarningInPage: function(text, category) {
if (this.activeTab && this.activeTab.traits.logInPage) {
const warningFlag = 1;
this.activeTab.logInPage({ text, category, flags: warningFlag });
this.activeTab.logInPage(text, category, warningFlag);
}
},
};

View File

@ -37,7 +37,7 @@ add_task(async function() {
const toolbox = await onToolboxReady;
const onToolboxDestroyed = gDevTools.once("toolbox-destroyed");
const onTabDetached = toolbox.target.activeTab.once("tabDetached");
const onTabDetached = once(toolbox.target.client, "tabDetached");
info("Removing the iframes");
toolboxIframe.remove();

View File

@ -115,6 +115,10 @@ function test() {
todo(false, "Front for " + actor + " still held in pool!");
continue;
}
// gcliActor is for the commandline which is separate to the toolbox
if (actor.includes("gcliActor")) {
continue;
}
ok(false, "Front for " + actor + " still held in pool!");
}
}

View File

@ -85,12 +85,11 @@ async function setDisableCacheCheckboxChecked(tabX, state) {
if (cbx.checked !== state) {
info("Setting disable cache checkbox to " + state + " for " + tabX.title);
const onReconfigured = tabX.toolbox.once("cache-reconfigured");
cbx.click();
// We have to wait for the reconfigure request to be finished before reloading
// the page.
await onReconfigured;
// We need to wait for all checkboxes to be updated and the docshells to
// apply the new cache settings.
await waitForTick();
}
}

View File

@ -460,7 +460,7 @@ OptionsPanel.prototype = {
}
if (this.target.activeTab && !this.target.chrome) {
const response = await this.target.activeTab.attach();
const [ response ] = await this.target.client.attachTarget(this.target.activeTab._actor);
this._origJavascriptEnabled = !response.javascriptEnabled;
this.disableJSNode.checked = this._origJavascriptEnabled;
this.disableJSNode.addEventListener("click", this._disableJSClicked);
@ -512,7 +512,7 @@ OptionsPanel.prototype = {
"javascriptEnabled": !checked
};
this.target.activeTab.reconfigure({ options });
this.target.activeTab.reconfigure(options);
},
destroy: function() {

View File

@ -1339,21 +1339,12 @@ Toolbox.prototype = {
* Apply the current cache setting from devtools.cache.disabled to this
* toolbox's tab.
*/
_applyCacheSettings: async function() {
_applyCacheSettings: function() {
const pref = "devtools.cache.disabled";
const cacheDisabled = Services.prefs.getBoolPref(pref);
if (this.target.activeTab) {
await this.target.activeTab.reconfigure({
options: {
"cacheDisabled": cacheDisabled
}
});
// This event is only emitted for tests in order to know when to reload
if (flags.testing) {
this.emit("cache-reconfigured");
}
this.target.activeTab.reconfigure({"cacheDisabled": cacheDisabled});
}
},
@ -1368,9 +1359,7 @@ Toolbox.prototype = {
if (this.target.activeTab) {
this.target.activeTab.reconfigure({
options: {
"serviceWorkersTestingEnabled": serviceWorkersTestingEnabled
}
"serviceWorkersTestingEnabled": serviceWorkersTestingEnabled
});
}
},
@ -1416,11 +1405,7 @@ Toolbox.prototype = {
this.telemetry.toolClosed("paintflashing", this.sessionId, this);
}
this.isPaintFlashing = !this.isPaintFlashing;
return this.target.activeTab.reconfigure({
options: {
"paintFlashing": this.isPaintFlashing
}
});
return this.target.activeTab.reconfigure({"paintFlashing": this.isPaintFlashing});
},
/**
@ -2343,7 +2328,7 @@ Toolbox.prototype = {
onSelectFrame: function(frameId) {
// Send packet to the backend to select specified frame and
// wait for 'frameUpdate' event packet to update the UI.
this.target.activeTab.switchToFrame({ windowId: frameId });
this.target.activeTab.switchToFrame(frameId);
},
/**

View File

@ -42,7 +42,7 @@ add_task(async function() {
info("Navigate to the slow loading page");
const activeTab = inspector.toolbox.target.activeTab;
await activeTab.navigateTo({ url: TEST_URL });
await activeTab.navigateTo(TEST_URL);
info("Wait for request made to the image");
const response = await onRequest;

View File

@ -48,7 +48,7 @@ var navigateTo = async function(inspector, url) {
info("Navigating to: " + url);
const activeTab = inspector.toolbox.target.activeTab;
await activeTab.navigateTo({ url });
await activeTab.navigateTo(url);
info("Waiting for markup view to load after navigation.");
await markuploaded;

View File

@ -316,7 +316,7 @@ class FirefoxConnector {
// Reconfigures the tab, optionally triggering a reload.
const reconfigureTab = options => {
return this.tabTarget.activeTab.reconfigure({ options });
return this.tabTarget.activeTab.reconfigure(options);
};
// Reconfigures the tab and waits for the target to finish navigating.

View File

@ -144,7 +144,7 @@ function toggleCache(target, disabled) {
// Disable the cache for any toolbox that it is opened from this point on.
Services.prefs.setBoolPref("devtools.cache.disabled", disabled);
return target.activeTab.reconfigure({ options }).then(() => navigationFinished);
return target.activeTab.reconfigure(options).then(() => navigationFinished);
}
/**

View File

@ -131,7 +131,7 @@ function navigateInHistory(aTarget, aDirection, aWaitForTargetEvent = "navigate"
}
function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") {
executeSoon(() => aTarget.activeTab.navigateTo({ url: aUrl }));
executeSoon(() => aTarget.activeTab.navigateTo(aUrl));
return once(aTarget, aWaitForTargetEvent);
}

View File

@ -11,41 +11,51 @@
var { DebuggerServer } = require("devtools/server/main");
var { DebuggerClient } = require("devtools/shared/client/debugger-client");
var { Task } = require("devtools/shared/task");
const TAB1_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
add_task(async function test() {
var gClient;
function test() {
DebuggerServer.init();
DebuggerServer.registerAllActors();
const transport = DebuggerServer.connectPipe();
const client = new DebuggerClient(transport);
const [type] = await client.connect();
is(type, "browser", "Root actor should identify itself as a browser.");
const tab = await addTab(TAB1_URL);
gClient = new DebuggerClient(transport);
gClient.connect().then(Task.async(function* ([aType, aTraits]) {
is(aType, "browser",
"Root actor should identify itself as a browser.");
const tab = yield addTab(TAB1_URL);
let { tabs } = await client.listTabs();
is(tabs.length, 2, "Should be two tabs");
const tabGrip = tabs.filter(a => a.url == TAB1_URL).pop();
ok(tabGrip, "Should have an actor for the tab");
let { tabs } = yield gClient.listTabs();
is(tabs.length, 2, "Should be two tabs");
const tabGrip = tabs.filter(a => a.url == TAB1_URL).pop();
ok(tabGrip, "Should have an actor for the tab");
let [response, targetFront] = await client.attachTarget(tabGrip.actor);
is(response.type, "tabAttached", "Should have attached");
let response = yield gClient.request({ to: tabGrip.actor, type: "attach" });
is(response.type, "tabAttached", "Should have attached");
response = await client.listTabs();
tabs = response.tabs;
response = yield gClient.listTabs();
tabs = response.tabs;
response = await targetFront.detach();
is(response.type, "detached", "Should have detached");
response = yield gClient.request({ to: tabGrip.actor, type: "detach" });
is(response.type, "detached", "Should have detached");
const newGrip = tabs.filter(a => a.url == TAB1_URL).pop();
is(newGrip.actor, tabGrip.actor, "Should have the same actor for the same tab");
const newGrip = tabs.filter(a => a.url == TAB1_URL).pop();
is(newGrip.actor, tabGrip.actor, "Should have the same actor for the same tab");
[response, targetFront] = await client.attachTarget(tabGrip.actor);
is(response.type, "tabAttached", "Should have attached");
response = await targetFront.detach();
is(response.type, "detached", "Should have detached");
response = yield gClient.request({ to: tabGrip.actor, type: "attach" });
is(response.type, "tabAttached", "Should have attached");
response = yield gClient.request({ to: tabGrip.actor, type: "detach" });
is(response.type, "detached", "Should have detached");
await removeTab(tab);
await client.close();
yield removeTab(tab);
yield gClient.close();
finish();
}));
}
registerCleanupFunction(function() {
gClient = null;
});

View File

@ -39,10 +39,10 @@ function test() {
});
}
function testNavigate(targetFront) {
function testNavigate([aGrip, aResponse]) {
const outstanding = [promise.defer(), promise.defer()];
targetFront.on("tabNavigated", function onTabNavigated(packet) {
gClient.addListener("tabNavigated", function onTabNavigated(event, packet) {
is(packet.url.split("/").pop(), TAB2_FILE,
"Got a tab navigation notification.");
@ -54,27 +54,27 @@ function testNavigate(targetFront) {
outstanding[0].resolve();
} else {
ok(true, "Tab finished navigating.");
targetFront.off("tabNavigated", onTabNavigated);
gClient.removeListener("tabNavigated", onTabNavigated);
outstanding[1].resolve();
}
});
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, TAB2_URL);
return promise.all(outstanding.map(e => e.promise))
.then(() => targetFront);
.then(() => aGrip.actor);
}
async function testDetach(targetFront) {
const onDetached = targetFront.once("tabDetached");
function testDetach(actor) {
const deferred = promise.defer();
gClient.addOneTimeListener("tabDetached", (type, packet) => {
ok(true, "Got a tab detach notification.");
is(packet.from, actor, "tab detach message comes from the expected actor");
deferred.resolve(gClient.close());
});
removeTab(gBrowser.selectedTab);
const packet = await onDetached;
ok(true, "Got a tab detach notification.");
is(packet.from, targetFront.actorID,
"tab detach message comes from the expected actor");
return gClient.close();
return deferred.promise;
}
registerCleanupFunction(function() {
@ -83,8 +83,8 @@ registerCleanupFunction(function() {
async function attachTargetActorForUrl(client, url) {
const grip = await getTargetActorForUrl(client, url);
const [, targetFront] = await client.attachTarget(grip.actor);
return targetFront;
const [ response ] = await client.attachTarget(grip.actor);
return [grip, response];
}
function getTargetActorForUrl(client, url) {

View File

@ -48,7 +48,7 @@ function reload(aTarget, aWaitForTargetEvent = "navigate") {
}
function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") {
executeSoon(() => aTarget.activeTab.navigateTo({ url: aUrl }));
executeSoon(() => aTarget.activeTab.navigateTo(aUrl));
return once(aTarget, aWaitForTargetEvent);
}

View File

@ -61,11 +61,15 @@ TabStore.prototype = {
// Watch for changes to remote browser tabs
this._connection.client.addListener("tabListChanged",
this._onTabListChanged);
this._connection.client.addListener("tabNavigated",
this._onTabNavigated);
this.listTabs();
} else {
if (this._connection.client) {
this._connection.client.removeListener("tabListChanged",
this._onTabListChanged);
this._connection.client.removeListener("tabNavigated",
this._onTabNavigated);
}
this._resetStore();
}

View File

@ -21,6 +21,8 @@ function start() {
// Start the client.
client = new DebuggerClient(transport);
// Attach listeners for client events.
client.addListener("tabNavigated", onTab);
client.connect((type, traits) => {
// Now the client is conected to the server.
debugTab();
@ -49,6 +51,9 @@ async function startClient() {
// Start the client.
client = new DebuggerClient(transport);
// Attach listeners for client events.
client.addListener("tabNavigated", onTab);
client.connect((type, traits) => {
// Now the client is conected to the server.
debugTab();
@ -84,9 +89,6 @@ function attachToTab() {
}
// Now the tabClient is ready and can be used.
// Attach listeners for client events.
tabClient.addListener("tabNavigated", onTab);
});
});
}
@ -103,7 +105,7 @@ async function onTab() {
// Detach from the previous thread.
await client.activeThread.detach();
// Detach from the previous tab.
await tabClient.activeTab.detach();
await client.activeTab.detach();
// Start debugging the new tab.
start();
}
@ -167,6 +169,8 @@ function startDebugger() {
// Start the client.
client = new DebuggerClient(transport);
// Attach listeners for client events.
client.addListener("tabNavigated", onTab);
client.connect((type, traits) => {
// Now the client is conected to the server.
debugTab();

View File

@ -966,7 +966,7 @@ const browsingContextTargetPrototype = {
// subsequent navigation event packet.
Services.tm.dispatchToMainThread(DevToolsUtils.makeInfallible(() => {
this.window.location = request.url;
}, "BrowsingContextTargetActor.prototype.navigateTo's delayed body:" + request.url));
}, "BrowsingContextTargetActor.prototype.navigateTo's delayed body"));
return {};
},

View File

@ -102,12 +102,12 @@ async function connectAndAttachTab() {
// Connect to this tab
const transport = DebuggerServer.connectPipe();
const client = new DebuggerClient(transport);
const form = await connectDebuggerClient(client);
const actorID = form.actor;
const [, targetFront ] = await client.attachTarget(actorID);
targetFront.on("tabNavigated", function(packet) {
client.addListener("tabNavigated", function(event, packet) {
assertEvent("tabNavigated", packet);
});
const form = await connectDebuggerClient(client);
const actorID = form.actor;
await client.attachTarget(actorID);
return { client, actorID };
}

View File

@ -26,7 +26,7 @@ async function setup(pageUrl) {
const { client, form } = target;
const [, targetFront] = await client.attachTarget(form.actor);
const [, tabClient] = await client.attachTarget(form.actor);
const [, consoleClient] = await client.attachConsole(form.consoleActor, []);
@ -34,7 +34,7 @@ async function setup(pageUrl) {
return {
client, form,
targetFront, consoleClient,
tabClient, consoleClient,
inspectedWindowFront,
extension, fakeExtCallerInfo,
};
@ -47,11 +47,11 @@ async function teardown({client, extension}) {
await extension.unload();
}
function waitForNextTabNavigated(targetFront) {
function waitForNextTabNavigated(client) {
return new Promise(resolve => {
targetFront.on("tabNavigated", function tabNavigatedListener(pkt) {
client.addListener("tabNavigated", function tabNavigatedListener(evt, pkt) {
if (pkt.state == "stop" && !pkt.isFrameSwitching) {
targetFront.off("tabNavigated", tabNavigatedListener);
client.removeListener("tabNavigated", tabNavigatedListener);
resolve();
}
});
@ -227,12 +227,12 @@ add_task(async function test_exception_inspectedWindowEval_result() {
add_task(async function test_exception_inspectedWindowReload() {
const {
client, consoleClient, inspectedWindowFront,
extension, fakeExtCallerInfo, targetFront,
extension, fakeExtCallerInfo,
} = await setup(`${TEST_RELOAD_URL}?test=cache`);
// Test reload with bypassCache=false.
const waitForNoBypassCacheReload = waitForNextTabNavigated(targetFront);
const waitForNoBypassCacheReload = waitForNextTabNavigated(client);
const reloadResult = await inspectedWindowFront.reload(fakeExtCallerInfo,
{ignoreCache: false});
@ -248,7 +248,7 @@ add_task(async function test_exception_inspectedWindowReload() {
// Test reload with bypassCache=true.
const waitForForceBypassCacheReload = waitForNextTabNavigated(targetFront);
const waitForForceBypassCacheReload = waitForNextTabNavigated(client);
await inspectedWindowFront.reload(fakeExtCallerInfo, {ignoreCache: true});
await waitForForceBypassCacheReload;
@ -265,12 +265,12 @@ add_task(async function test_exception_inspectedWindowReload() {
add_task(async function test_exception_inspectedWindowReload_customUserAgent() {
const {
client, consoleClient, inspectedWindowFront,
extension, fakeExtCallerInfo, targetFront,
extension, fakeExtCallerInfo,
} = await setup(`${TEST_RELOAD_URL}?test=user-agent`);
// Test reload with custom userAgent.
const waitForCustomUserAgentReload = waitForNextTabNavigated(targetFront);
const waitForCustomUserAgentReload = waitForNextTabNavigated(client);
await inspectedWindowFront.reload(fakeExtCallerInfo,
{userAgent: "Customized User Agent"});
@ -284,7 +284,7 @@ add_task(async function test_exception_inspectedWindowReload_customUserAgent() {
// Test reload with no custom userAgent.
const waitForNoCustomUserAgentReload = waitForNextTabNavigated(targetFront);
const waitForNoCustomUserAgentReload = waitForNextTabNavigated(client);
await inspectedWindowFront.reload(fakeExtCallerInfo, {});
await waitForNoCustomUserAgentReload;
@ -301,12 +301,12 @@ add_task(async function test_exception_inspectedWindowReload_customUserAgent() {
add_task(async function test_exception_inspectedWindowReload_injectedScript() {
const {
client, consoleClient, inspectedWindowFront,
extension, fakeExtCallerInfo, targetFront,
extension, fakeExtCallerInfo,
} = await setup(`${TEST_RELOAD_URL}?test=injected-script&frames=3`);
// Test reload with an injectedScript.
const waitForInjectedScriptReload = waitForNextTabNavigated(targetFront);
const waitForInjectedScriptReload = waitForNextTabNavigated(client);
await inspectedWindowFront.reload(fakeExtCallerInfo,
{injectedScript: `new ${injectedScript}`});
await waitForInjectedScriptReload;
@ -321,7 +321,7 @@ add_task(async function test_exception_inspectedWindowReload_injectedScript() {
// Test reload without an injectedScript.
const waitForNoInjectedScriptReload = waitForNextTabNavigated(targetFront);
const waitForNoInjectedScriptReload = waitForNextTabNavigated(client);
await inspectedWindowFront.reload(fakeExtCallerInfo, {});
await waitForNoInjectedScriptReload;
@ -339,13 +339,13 @@ add_task(async function test_exception_inspectedWindowReload_injectedScript() {
add_task(async function test_exception_inspectedWindowReload_multiple_calls() {
const {
client, consoleClient, inspectedWindowFront,
extension, fakeExtCallerInfo, targetFront,
extension, fakeExtCallerInfo,
} = await setup(`${TEST_RELOAD_URL}?test=user-agent`);
// Test reload with custom userAgent three times (and then
// check that only the first one has affected the page reload.
const waitForCustomUserAgentReload = waitForNextTabNavigated(targetFront);
const waitForCustomUserAgentReload = waitForNextTabNavigated(client);
inspectedWindowFront.reload(fakeExtCallerInfo, {userAgent: "Customized User Agent 1"});
inspectedWindowFront.reload(fakeExtCallerInfo, {userAgent: "Customized User Agent 2"});
@ -360,7 +360,7 @@ add_task(async function test_exception_inspectedWindowReload_multiple_calls() {
// Test reload with no custom userAgent.
const waitForNoCustomUserAgentReload = waitForNextTabNavigated(targetFront);
const waitForNoCustomUserAgentReload = waitForNextTabNavigated(client);
await inspectedWindowFront.reload(fakeExtCallerInfo, {});
await waitForNoCustomUserAgentReload;
@ -377,12 +377,12 @@ add_task(async function test_exception_inspectedWindowReload_multiple_calls() {
add_task(async function test_exception_inspectedWindowReload_stopped() {
const {
client, consoleClient, inspectedWindowFront,
extension, fakeExtCallerInfo, targetFront,
extension, fakeExtCallerInfo,
} = await setup(`${TEST_RELOAD_URL}?test=injected-script&frames=3`);
// Test reload on a page that calls window.stop() immediately during the page loading
const waitForPageLoad = waitForNextTabNavigated(targetFront);
const waitForPageLoad = waitForNextTabNavigated(client);
await inspectedWindowFront.eval(fakeExtCallerInfo,
"window.location += '&stop=windowStop'");
@ -390,7 +390,7 @@ add_task(async function test_exception_inspectedWindowReload_stopped() {
await waitForPageLoad;
info("Starting a reload with an injectedScript");
const waitForInjectedScriptReload = waitForNextTabNavigated(targetFront);
const waitForInjectedScriptReload = waitForNextTabNavigated(client);
await inspectedWindowFront.reload(fakeExtCallerInfo,
{injectedScript: `new ${injectedScript}`});
await waitForInjectedScriptReload;
@ -408,7 +408,7 @@ add_task(async function test_exception_inspectedWindowReload_stopped() {
// Reload again with no options.
info("Reload the tab again without any reload options");
const waitForNoInjectedScriptReload = waitForNextTabNavigated(targetFront);
const waitForNoInjectedScriptReload = waitForNextTabNavigated(client);
await inspectedWindowFront.reload(fakeExtCallerInfo, {});
await waitForNoInjectedScriptReload;

View File

@ -42,6 +42,7 @@ async function test_connect_addon(oopMode) {
ok(addonTargetActor, "The expected webextension addon actor has been found");
// Connect to the target addon actor and wait for the updated list of frames.
const waitFramesUpdated = waitForFramesUpdated({client});
const addonTarget = await TargetFactory.forRemoteTab({
form: addonTargetActor,
client,
@ -49,7 +50,7 @@ async function test_connect_addon(oopMode) {
});
is(addonTarget.form.isOOP, oopMode,
"Got the expected oop mode in the webextension actor form");
const frames = await waitForFramesUpdated(addonTarget);
const frames = await waitFramesUpdated;
const backgroundPageFrame = frames.filter((frame) => {
return frame.url && frame.url.endsWith("/_generated_background_page.html");
}).pop();

View File

@ -51,19 +51,19 @@ function setWebExtensionOOPMode(oopMode) {
});
}
function waitForFramesUpdated(target, matchFn) {
function waitForFramesUpdated({client}, matchFn) {
return new Promise(resolve => {
const listener = data => {
const listener = (evt, data) => {
if (typeof matchFn === "function" && !matchFn(data)) {
return;
} else if (!data.frames) {
return;
}
target.activeTab.off("frameUpdate", listener);
client.removeListener("frameUpdate", listener);
resolve(data.frames);
};
target.activeTab.on("frameUpdate", listener);
client.addListener("frameUpdate", listener);
});
}

View File

@ -44,7 +44,7 @@ function test_simple_source_map() {
expectedSources.delete(packet.source.url);
if (expectedSources.size === 0) {
gThreadClient.removeListener("newSource", _onNewSource);
gClient.removeListener("newSource", _onNewSource);
finishClient(gClient);
}
});

View File

@ -33,16 +33,13 @@ const UnsolicitedNotifications = {
"addonListChanged": "addonListChanged",
"workerListChanged": "workerListChanged",
"serviceWorkerRegistrationListChanged": "serviceWorkerRegistrationList",
"tabNavigated": "tabNavigated",
"frameUpdate": "frameUpdate",
"pageError": "pageError",
"evaluationResult": "evaluationResult",
"updatedSource": "updatedSource",
"inspectObject": "inspectObject",
// newSource is still emitted on the ThreadActor, in addition to the
// BrowsingContextActor we have to keep it here until ThreadClient is converted to
// ThreadFront and/or we stop emitting this duplicated events.
// See ThreadActor.onNewSourceEvent.
"newSource": "newSource",
"updatedSource": "updatedSource",
"inspectObject": "inspectObject"
};
/**

View File

@ -24,11 +24,10 @@ loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
loader.lazyRequireGetter(this, "WebConsoleClient", "devtools/shared/webconsole/client", true);
loader.lazyRequireGetter(this, "AddonClient", "devtools/shared/client/addon-client");
loader.lazyRequireGetter(this, "RootClient", "devtools/shared/client/root-client");
loader.lazyRequireGetter(this, "BrowsingContextFront", "devtools/shared/fronts/targets/browsing-context", true);
loader.lazyRequireGetter(this, "TabClient", "devtools/shared/client/tab-client");
loader.lazyRequireGetter(this, "ThreadClient", "devtools/shared/client/thread-client");
loader.lazyRequireGetter(this, "WorkerClient", "devtools/shared/client/worker-client");
loader.lazyRequireGetter(this, "ObjectClient", "devtools/shared/client/object-client");
loader.lazyRequireGetter(this, "Pool", "devtools/shared/protocol", true);
// Retrieve the major platform version, i.e. if we are on Firefox 64.0a1, it will be 64.
const PLATFORM_MAJOR_VERSION = AppConstants.MOZ_APP_VERSION.match(/\d+/)[0];
@ -51,19 +50,8 @@ function DebuggerClient(transport) {
this._transport.hooks = this;
// Map actor ID to client instance for each actor type.
// To be removed once all clients are refactored to protocol.js
this._clients = new Map();
// Pool of fronts instanciated by this class.
// This is useful for actors that have already been transitioned to protocol.js
// Once RootClient becomes a protocol.js actor, these actors can be attached to it
// instead of this pool.
// This Pool will automatically be added to this._pools via addActorPool once the first
// Front will be added to it (in attachTarget, attachWorker,...).
// And it does not need to destroyed explicitly as all Pools are destroyed on client
// closing.
this._frontPool = new Pool(this);
this._pendingRequests = new Map();
this._activeRequests = new Map();
this._eventsEnabled = true;
@ -296,9 +284,7 @@ DebuggerClient.prototype = {
this._eventsEnabled = false;
const cleanup = () => {
if (this._transport) {
this._transport.close();
}
this._transport.close();
this._transport = null;
};
@ -368,15 +354,29 @@ DebuggerClient.prototype = {
* @param string targetActor
* The target actor ID for the tab to attach.
*/
attachTarget: async function(targetActor) {
let front = this._frontPool.actor(targetActor);
if (!front) {
front = new BrowsingContextFront(this, { actor: targetActor });
this._frontPool.manage(front);
attachTarget: function(targetActor) {
if (this._clients.has(targetActor)) {
const cachedTarget = this._clients.get(targetActor);
const cachedResponse = {
cacheDisabled: cachedTarget.cacheDisabled,
javascriptEnabled: cachedTarget.javascriptEnabled,
traits: cachedTarget.traits,
};
return promise.resolve([cachedResponse, cachedTarget]);
}
const response = await front.attach();
return [response, front];
const packet = {
to: targetActor,
type: "attach"
};
return this.request(packet).then(response => {
// TabClient can actually represent targets other than a tab.
// It is planned to be renamed while being converted to a front
// in bug 1485660.
const targetClient = new TabClient(this, response);
this.registerClient(targetClient);
return [response, targetClient];
});
},
attachWorker: function(workerTargetActor) {

View File

@ -19,6 +19,7 @@ DevToolsModules(
'root-client.js',
'source-client.js',
'symbol-iterator-client.js',
'tab-client.js',
'thread-client.js',
'worker-client.js',
)

View File

@ -0,0 +1,163 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const promise = require("devtools/shared/deprecated-sync-thenables");
const eventSource = require("devtools/shared/client/event-source");
const {arg, DebuggerClient} = require("devtools/shared/client/debugger-client");
loader.lazyRequireGetter(this, "ThreadClient", "devtools/shared/client/thread-client");
/**
* Creates a tab client for the remote debugging protocol server. This client is a front
* to the target actor for a tab created in the server side, hiding the protocol details
* in a traditional JavaScript API.
*
* @param client DebuggerClient
* The debugger client parent.
* @param form object
* The protocol form for this tab.
*/
function TabClient(client, form) {
this.client = client;
this._actor = form.from;
this._threadActor = form.threadActor;
this.javascriptEnabled = form.javascriptEnabled;
this.cacheDisabled = form.cacheDisabled;
this.thread = null;
this.request = this.client.request;
this.traits = form.traits || {};
this.events = ["workerListChanged"];
}
TabClient.prototype = {
get actor() {
return this._actor;
},
get _transport() {
return this.client._transport;
},
/**
* Attach to a thread actor.
*
* @param object options
* Configuration options.
* - useSourceMaps: whether to use source maps or not.
*/
attachThread: function(options = {}) {
if (this.thread) {
return promise.resolve([{}, this.thread]);
}
const packet = {
to: this._threadActor,
type: "attach",
options,
};
return this.request(packet).then(response => {
this.thread = new ThreadClient(this, this._threadActor);
this.client.registerClient(this.thread);
return [response, this.thread];
});
},
/**
* Detach the client from the target actor.
*/
detach: DebuggerClient.requester({
type: "detach"
}, {
before: function(packet) {
if (this.thread) {
this.thread.detach();
}
return packet;
},
after: function(response) {
this.client.unregisterClient(this);
return response;
},
}),
/**
* Bring the window to the front.
*/
focus: DebuggerClient.requester({
type: "focus"
}, {}),
/**
* Ensure relevant pages have error reporting enabled.
*/
ensureCSSErrorReportingEnabled: DebuggerClient.requester({
type: "ensureCSSErrorReportingEnabled",
}, {}),
/**
* Reload the page in this tab.
*
* @param [optional] object options
* An object with a `force` property indicating whether or not
* this reload should skip the cache
*/
reload: function(options = { force: false }) {
return this._reload(options);
},
_reload: DebuggerClient.requester({
type: "reload",
options: arg(0)
}),
/**
* Navigate to another URL.
*
* @param string url
* The URL to navigate to.
*/
navigateTo: DebuggerClient.requester({
type: "navigateTo",
url: arg(0)
}),
/**
* Reconfigure the target actor.
*
* @param object options
* A dictionary object of the new options to use in the target actor.
*/
reconfigure: DebuggerClient.requester({
type: "reconfigure",
options: arg(0)
}),
listWorkers: DebuggerClient.requester({
type: "listWorkers"
}),
attachWorker: function(workerTargetActor) {
return this.client.attachWorker(workerTargetActor);
},
logInPage: DebuggerClient.requester({
type: "logInPage",
text: arg(0),
category: arg(1),
flags: arg(2),
}),
listFrames: DebuggerClient.requester({
type: "listFrames",
}),
switchToFrame: DebuggerClient.requester({
type: "switchToFrame",
windowId: arg(0),
}),
};
eventSource(TabClient.prototype);
module.exports = TabClient;

View File

@ -25,7 +25,7 @@ const noop = () => {};
* is a front to the thread actor created in the server side, hiding the
* protocol details in a traditional JavaScript API.
*
* @param client DebuggerClient, WorkerClient or BrowsingContextFront
* @param client DebuggerClient|TabClient
* The parent of the thread (tab for target-scoped debuggers,
* DebuggerClient for chrome debuggers).
* @param actor string

View File

@ -6,7 +6,6 @@
DIRS += [
'addon',
'targets',
]
DevToolsModules(

View File

@ -1,88 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {browsingContextTargetSpec} = require("devtools/shared/specs/targets/browsing-context");
const protocol = require("devtools/shared/protocol");
const {custom} = protocol;
loader.lazyRequireGetter(this, "ThreadClient", "devtools/shared/client/thread-client");
const BrowsingContextFront = protocol.FrontClassWithSpec(browsingContextTargetSpec, {
initialize: function(client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
this.thread = null;
// TODO: remove once ThreadClient becomes a front
this.client = client;
},
/**
* Attach to a thread actor.
*
* @param object options
* Configuration options.
* - useSourceMaps: whether to use source maps or not.
*/
attachThread: function(options = {}) {
if (this.thread) {
return Promise.resolve([{}, this.thread]);
}
const packet = {
to: this._threadActor,
type: "attach",
options,
};
return this.client.request(packet).then(response => {
this.thread = new ThreadClient(this, this._threadActor);
this.client.registerClient(this.thread);
return [response, this.thread];
});
},
attach: custom(async function() {
const response = await this._attach();
this._threadActor = response.threadActor;
this.javascriptEnabled = response.javascriptEnabled;
this.cacheDisabled = response.cacheDisabled;
this.traits = response.traits || {};
return response;
}, {
impl: "_attach"
}),
detach: custom(async function() {
let response;
try {
response = await this._detach();
} catch (e) {
console.warn(
`Error while detaching the browsing context target front: ${e.message}`);
}
if (this.thread) {
try {
await this.thread.detach();
} catch (e) {
console.warn(`Error while detaching the thread front: ${e.message}`);
}
}
this.destroy();
return response;
}, {
impl: "_detach"
}),
attachWorker: function(workerTargetActor) {
return this.client.attachWorker(workerTargetActor);
},
});
exports.BrowsingContextFront = BrowsingContextFront;

View File

@ -1,9 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'browsing-context.js',
)

View File

@ -1352,10 +1352,7 @@ Front.prototype = extend(Pool.prototype, {
} else {
this.actor().then(actorID => {
packet.to = actorID;
// The connection might be closed during the promise resolution
if (this.conn._transport) {
this.conn._transport.send(packet);
}
this.conn._transport.send(packet);
}).catch(console.error);
}
},

View File

@ -127,17 +127,10 @@ const browsingContextTargetSpecPrototype = {
destroyAll: Option(0, "nullable:boolean")
},
tabDetached: {
type: "tabDetached",
// This is to make browser_dbg_navigation.js to work as it expect to
// see a packet object when listening for tabDetached
from: Option(0, "string"),
type: "tabDetached"
},
workerListChanged: {
type: "workerListChanged"
},
newSource: {
type: "newSource",
source: Option(0, "json")
}
}
};