summaryrefslogtreecommitdiffstats
path: root/devtools/shared/commands/object/tests/browser_object.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/shared/commands/object/tests/browser_object.js')
-rw-r--r--devtools/shared/commands/object/tests/browser_object.js125
1 files changed, 125 insertions, 0 deletions
diff --git a/devtools/shared/commands/object/tests/browser_object.js b/devtools/shared/commands/object/tests/browser_object.js
new file mode 100644
index 0000000000..9f6d5132d3
--- /dev/null
+++ b/devtools/shared/commands/object/tests/browser_object.js
@@ -0,0 +1,125 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test the ObjectCommand
+
+add_task(async function testObjectRelease() {
+ const tab = await addTab("data:text/html;charset=utf-8,Test page<script>var foo = { bar: 42 };</script>");
+
+ const commands = await CommandsFactory.forTab(tab);
+ await commands.targetCommand.startListening();
+
+ const { objectCommand } = commands;
+
+ const evaluationResponse = await commands.scriptCommand.execute(
+ "window.foo"
+ );
+
+ // Execute a second time so that the WebConsoleActor set this._lastConsoleInputEvaluation to another value
+ // and so we prevent freeing `window.foo`
+ await commands.scriptCommand.execute("");
+
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () {
+ is(content.wrappedJSObject.foo.bar, 42);
+ const weakRef = Cu.getWeakReference(content.wrappedJSObject.foo);
+
+ // Hold off the weak reference on SpecialPowsers so that it can be accessed in the next SpecialPowers.spawn
+ SpecialPowers.weakRef = weakRef;
+
+ // Nullify this variable so that it should be freed
+ // unless the DevTools inspection still hold it in memory
+ content.wrappedJSObject.foo = null;
+
+ Cu.forceGC();
+ Cu.forceCC();
+
+ ok(SpecialPowers.weakRef.get(), "The 'foo' object can't be freed because of DevTools keeping a reference on it");
+ });
+
+ info("Release the server side actors which are keeping the object in memory");
+ const objectFront = evaluationResponse.result;
+ await commands.objectCommand.releaseObjects([objectFront]);
+
+ ok(objectFront.isDestroyed(), "The passed object front has been destroyed");
+
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () {
+ await ContentTaskUtils.waitForCondition(() => {
+ Cu.forceGC();
+ Cu.forceCC();
+ return !SpecialPowers.weakRef.get();
+ }, "Wait for JS object to be freed", 500);
+
+ ok(!SpecialPowers.weakRef.get(), "The 'foo' object has been freed");
+ });
+
+ await commands.destroy();
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function testMultiTargetObjectRelease() {
+ // This test fails with EFT disabled
+ if (!isEveryFrameTargetEnabled()) {
+ return;
+ }
+
+ const tab = await addTab(`data:text/html;charset=utf-8,Test page<iframe src="data:text/html,bar">/iframe>`);
+
+ const commands = await CommandsFactory.forTab(tab);
+ await commands.targetCommand.startListening();
+
+ const [,iframeTarget] = commands.targetCommand.getAllTargets(commands.targetCommand.ALL_TYPES);
+ is(iframeTarget.url, "data:text/html,bar");
+
+ const { objectCommand } = commands;
+
+ const evaluationResponse1 = await commands.scriptCommand.execute(
+ "window"
+ );
+ const evaluationResponse2 = await commands.scriptCommand.execute(
+ "window", {
+ selectedTargetFront: iframeTarget,
+ }
+ );
+ const object1 = evaluationResponse1.result;
+ const object2 = evaluationResponse2.result;
+ isnot(object1, object2, "The two window object fronts are different");
+ isnot(object1.targetFront, object2.targetFront, "The two window object fronts relates to two distinct targets");
+ is(object2.targetFront, iframeTarget, "The second object relates to the iframe target");
+
+ await commands.objectCommand.releaseObjects([object1, object2]);
+ ok(object1.isDestroyed(), "The first object front is destroyed");
+ ok(object2.isDestroyed(), "The second object front is destroyed");
+
+ await commands.destroy();
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function testWorkerObjectRelease() {
+ const workerUrl = `data:text/javascript,const foo = {}`;
+ const tab = await addTab(`data:text/html;charset=utf-8,Test page<script>const worker = new Worker("${workerUrl}")</script>`);
+
+ const commands = await CommandsFactory.forTab(tab);
+ commands.targetCommand.listenForWorkers = true;
+ await commands.targetCommand.startListening();
+
+ const [,workerTarget] = commands.targetCommand.getAllTargets(commands.targetCommand.ALL_TYPES);
+ is(workerTarget.url, workerUrl);
+
+ const { objectCommand } = commands;
+
+ const evaluationResponse = await commands.scriptCommand.execute(
+ "foo", {
+ selectedTargetFront: workerTarget,
+ }
+ );
+ const object = evaluationResponse.result;
+ is(object.targetFront, workerTarget, "The 'foo' object relates to the worker target");
+
+ await commands.objectCommand.releaseObjects([object]);
+ ok(object.isDestroyed(), "The object front is destroyed");
+
+ await commands.destroy();
+ BrowserTestUtils.removeTab(tab);
+});