/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; /** * Test Front.watchFronts method. */ const protocol = require("devtools/shared/protocol"); const { RetVal } = protocol; const childSpec = protocol.generateActorSpec({ typeName: "childActor", methods: { release: { release: true, }, }, }); const ChildActor = protocol.ActorClassWithSpec(childSpec, { initialize(conn, id) { protocol.Actor.prototype.initialize.call(this, conn); this.childID = id; }, release() {}, form: function() { return { actor: this.actorID, childID: this.childID, foo: "bar", }; }, }); const rootSpec = protocol.generateActorSpec({ typeName: "root", methods: { createChild: { request: {}, response: { actor: RetVal("childActor") }, }, }, }); const RootActor = protocol.ActorClassWithSpec(rootSpec, { typeName: "root", initialize: function(conn) { protocol.Actor.prototype.initialize.call(this, conn); this.actorID = "root"; // Root actor owns itself. this.manage(this); this.sequence = 0; }, sayHello() { return { from: "root", applicationType: "xpcshell-tests", traits: [], }; }, createChild() { return new ChildActor(this.conn, this.sequence++); }, }); class ChildFront extends protocol.FrontClassWithSpec(childSpec) { form(form) { this.childID = form.childID; this.foo = form.foo; } } protocol.registerFront(ChildFront); class RootFront extends protocol.FrontClassWithSpec(rootSpec) { constructor(client) { super(client); this.actorID = "root"; // Root owns itself. this.manage(this); } } protocol.registerFront(RootFront); add_task(async function run_test() { DevToolsServer.createRootActor = RootActor; DevToolsServer.init(); const trace = connectPipeTracing(); const client = new DevToolsClient(trace); await client.connect(); const rootFront = client.mainRoot; const fronts = []; const listener = front => { equal( front.foo, "bar", "Front's form is set before watchFronts listeners are called" ); fronts.push(front); }; rootFront.watchFronts("childActor", listener); const firstChild = await rootFront.createChild(); ok( firstChild instanceof ChildFront, "createChild returns a ChildFront instance" ); equal(firstChild.childID, 0, "First child has ID=0"); equal( fronts.length, 1, "watchFronts fires the callback, even if the front is created in the future" ); equal( fronts[0], firstChild, "watchFronts fires the callback with the right front instance" ); const watchFrontsAfter = await new Promise(resolve => { rootFront.watchFronts("childActor", resolve); }); equal( watchFrontsAfter, firstChild, "watchFronts fires the callback, even if the front is already created, " + " with the same front instance" ); equal( fronts.length, 1, "There is still only one front reported from the first listener" ); const secondChild = await rootFront.createChild(); equal( fronts.length, 2, "After a second call to createChild, two fronts are reported" ); equal(fronts[1], secondChild, "And the new front is the right instance"); // Test unregistering a front listener rootFront.unwatchFronts("childActor", listener); const thirdChild = await rootFront.createChild(); equal( fronts.length, 2, "After calling unwatchFronts, the listener is no longer called" ); // Test front destruction const destroyed = []; rootFront.watchFronts("childActor", null, front => { destroyed.push(front); }); await thirdChild.release(); equal( destroyed.length, 1, "After the destruction of the front, one destruction is reported" ); equal(destroyed[0], thirdChild, "And the destroyed front is the right one"); trace.close(); await client.close(); });