author | Gabriel Luong <gabriel.luong@gmail.com> |
Wed, 10 Jun 2015 00:18:48 -0700 | |
changeset 248117 | 57ec499fafb57645f5aa26ab8a9e2247a258cfb2 |
parent 248116 | ae4f4b3fd22f0ff16501329eb980afce496aafa0 |
child 248118 | a01b1fbc61e9a91cb1c2ce17147a88ce15d10a9c |
push id | 60888 |
push user | kwierso@gmail.com |
push date | Thu, 11 Jun 2015 01:38:38 +0000 |
treeherder | mozilla-inbound@39e638ed06bf [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | fitzgen |
bugs | 1084525 |
milestone | 41.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/toolkit/devtools/client/dbg-client.jsm +++ b/toolkit/devtools/client/dbg-client.jsm @@ -2411,16 +2411,31 @@ ObjectClient.prototype = { }, { before: function (aPacket) { if (this._grip.class !== "Function") { throw new Error("scope is only valid for function grips."); } return aPacket; }, telemetry: "SCOPE" + }), + + /** + * Request the promises directly depending on the current promise. + */ + getDependentPromises: DebuggerClient.requester({ + type: "dependentPromises" + }, { + before: function(aPacket) { + if (this._grip.class !== "Promise") { + throw new Error("getDependentPromises is only valid for promise " + + "grips."); + } + return aPacket; + } }) }; /** * A PropertyIteratorClient provides a way to access to property names and * values of an object efficiently, slice by slice. * Note that the properties can be sorted in the backend, * this is controled while creating the PropertyIteratorClient
--- a/toolkit/devtools/server/actors/object.js +++ b/toolkit/devtools/server/actors/object.js @@ -513,31 +513,54 @@ ObjectActor.prototype = { let envActor = this.hooks.createEnvironmentActor(this.obj.environment, this.registeredPool); if (!envActor) { return { error: "notDebuggee", message: "cannot access the environment of this function." }; } return { from: this.actorID, scope: envActor.form() }; + }, + + /** + * Handle a protocol request to get the list of dependent promises of a + * promise. + * + * @return object + * Returns an object containing an array of object grips of the + * dependent promises + */ + onDependentPromises: function() { + if (this.obj.class != "Promise") { + return { error: "objectNotPromise", + message: "'dependentPromises' request is only valid for " + + "object grips with a 'Promise' class." }; + } + + let rawPromise = this.obj.unsafeDereference(); + let promises = PromiseDebugging.getDependentPromises(rawPromise).map(p => + this.hooks.createValueGrip(this.obj.makeDebuggeeValue(p))); + + return { promises }; } }; ObjectActor.prototype.requestTypes = { "definitionSite": ObjectActor.prototype.onDefinitionSite, "parameterNames": ObjectActor.prototype.onParameterNames, "prototypeAndProperties": ObjectActor.prototype.onPrototypeAndProperties, "enumProperties": ObjectActor.prototype.onEnumProperties, "prototype": ObjectActor.prototype.onPrototype, "property": ObjectActor.prototype.onProperty, "displayString": ObjectActor.prototype.onDisplayString, "ownPropertyNames": ObjectActor.prototype.onOwnPropertyNames, "decompile": ObjectActor.prototype.onDecompile, "release": ObjectActor.prototype.onRelease, "scope": ObjectActor.prototype.onScope, + "dependentPromises": ObjectActor.prototype.onDependentPromises }; /** * Creates an actor to iterate over an object's property names and values. * * @param objectActor ObjectActor * The object actor. * @param options Object
new file mode 100644 --- /dev/null +++ b/toolkit/devtools/server/tests/unit/test_promises_client_getdependentpromises.js @@ -0,0 +1,110 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Test that we can get the list of dependent promises from the ObjectClient. + */ + +"use strict"; + +const { PromisesFront } = devtools.require("devtools/server/actors/promises"); + +let events = devtools.require("sdk/event/core"); + +add_task(function*() { + let client = yield startTestDebuggerServer("test-promises-dependentpromises"); + let chromeActors = yield getChromeActors(client); + + ok(Promise.toString().contains("native code"), "Expect native DOM Promise."); + + yield testGetDependentPromises(client, chromeActors, () => { + let p = new Promise(() => {}); + p.name = "p"; + let q = p.then(); + q.name = "q"; + let r = p.then(null, () => {}); + r.name = "r"; + + return p; + }); + + let response = yield listTabs(client); + let targetTab = findTab(response.tabs, "test-promises-dependentpromises"); + ok(targetTab, "Found our target tab."); + + yield testGetDependentPromises(client, targetTab, () => { + const debuggee = + DebuggerServer.getTestGlobal("test-promises-dependentpromises"); + + let p = new debuggee.Promise(() => {}); + p.name = "p"; + let q = p.then(); + q.name = "q"; + let r = p.then(null, () => {}); + r.name = "r"; + + return p; + }); + + yield close(client); +}); + +function* testGetDependentPromises(client, form, makePromises) { + let front = PromisesFront(client, form); + + yield front.attach(); + yield front.listPromises(); + + // Get the grip for promise p + let onNewPromise = new Promise(resolve => { + events.on(front, "new-promises", promises => { + for (let p of promises) { + if (p.preview.ownProperties.name && + p.preview.ownProperties.name.value === "p") { + resolve(p); + } + } + }); + }); + + let promise = makePromises(); + + let grip = yield onNewPromise; + ok(grip, "Found our promise p."); + + let objectClient = new ObjectClient(client, grip); + ok(objectClient, "Got Object Client."); + + // Get the dependent promises for promise p and assert that the list of + // dependent promises is correct + yield new Promise(resolve => { + objectClient.getDependentPromises(response => { + let dependentNames = response.promises.map(p => + p.preview.ownProperties.name.value); + let expectedDependentNames = ["q", "r"]; + + equal(dependentNames.length, expectedDependentNames.length, + "Got expected number of dependent promises."); + + for (let i = 0; i < dependentNames.length; i++) { + equal(dependentNames[i], expectedDependentNames[i], + "Got expected dependent name."); + } + + for (let p of response.promises) { + equal(p.type, "object", "Expect type to be Object."); + equal(p.class, "Promise", "Expect class to be Promise."); + equal(typeof p.promiseState.creationTimestamp, "number", + "Expect creation timestamp to be a number."); + ok(!p.promiseState.timeToSettle, + "Expect time to settle to be undefined."); + } + + resolve(); + }); + }); + + yield front.detach(); + // Appease eslint + void promise; +}
--- a/toolkit/devtools/server/tests/unit/xpcshell.ini +++ b/toolkit/devtools/server/tests/unit/xpcshell.ini @@ -80,16 +80,17 @@ support-files = [test_eval-03.js] [test_eval-04.js] [test_eval-05.js] [test_promises_actor_attach.js] [test_promises_actor_exist.js] [test_promises_actor_list_promises.js] [test_promises_actor_onnewpromise.js] [test_promises_actor_onpromisesettled.js] +[test_promises_client_getdependentpromises.js] [test_promises_object_creationtimestamp.js] [test_promises_object_timetosettle-01.js] [test_promises_object_timetosettle-02.js] [test_protocol_abort.js] [test_protocol_async.js] [test_protocol_children.js] [test_protocol_formtype.js] [test_protocol_longstring.js]