Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
/* Any copyright is dedicated to the Public Domain.
"use strict";
const { dumpScope } = ChromeUtils.importESModule(
"resource://devtools/shared/test-helpers/dump-scope.sys.mjs",
{ global: "devtools" }
);
function nestedSync1() {
/* eslint-disable no-unused-vars */
const a = { prop: 1 };
const b = [1, 2, 3];
const c = function () {};
/* eslint-enable no-unused-vars */
return nestedSync2();
}
function nestedSync2() {
/* eslint-disable no-unused-vars */
const d = { prop: -1 };
const e = ["4", "5", "6"];
const f = new Uint8Array([7, 8, 9]);
/* eslint-enable no-unused-vars */
return dumpScope({ saveAsFile: false });
}
add_task(async function testSyncStack() {
const scopes = await nestedSync1();
is(scopes.length, 3, "dumpScope returned 3 frames");
// Test frame for nestedSync1
const testScope1 = scopes[1];
assertScopeInformation(testScope1);
let scope = testScope1.scope;
is(typeof scope.a, "object", "Object type is correct");
is(scope.a.prop, "1", "Object property value is correct");
is(typeof scope.b, "object");
ok(Array.isArray(scope.b));
is(scope.b[0], "1", "Array of number value is correct");
is(scope.b[1], "2", "Array of number value is correct");
is(scope.b[2], "3", "Array of number value is correct");
is(typeof scope.c, "string", "Function type is correct");
is(scope.c, "Function c", "Function value is correct");
// Test frame for nestedSync2
const testScope2 = scopes[0];
assertScopeInformation(testScope2);
scope = testScope2.scope;
is(typeof scope.d, "object", "Object type is correct");
is(scope.d.prop, "-1", "Object property value is correct");
// Check regular array of strings
is(typeof scope.e, "object");
ok(Array.isArray(scope.e), "Array of string type is correct");
is(scope.e[0], "4", "Array of string value is correct");
is(scope.e[1], "5", "Array of string value is correct");
is(scope.e[2], "6", "Array of string value is correct");
// Check typed array
is(typeof scope.e, "object");
ok(Array.isArray(scope.f), "Typed array type is correct");
is(scope.f[0], "7", "Typed array value is correct");
is(scope.f[1], "8", "Typed array value is correct");
is(scope.f[2], "9", "Typed array value is correct");
});
async function nestedAsync1() {
// eslint-disable-next-line no-unused-vars
const asyncA = 1;
const scopes = await nestedAsync2();
return scopes;
}
async function nestedAsync2() {
// eslint-disable-next-line no-unused-vars
const asyncB = 2;
const scopes = await nestedAsync3();
return scopes;
}
async function nestedAsync3() {
// eslint-disable-next-line no-unused-vars
const asyncC = 3;
return dumpScope({ saveAsFile: false });
}
add_task(async function testAsyncStack() {
const scopes = await nestedAsync1();
is(scopes.length, 4, "dumpScope returned 4 frames");
const testScope1 = scopes[2];
assertScopeInformation(testScope1);
is(testScope1.scope.asyncA, "1", "Async frame value is correct");
const testScope2 = scopes[1];
assertScopeInformation(testScope2);
is(testScope2.scope.asyncB, "2", "Async frame value is correct");
const testScope3 = scopes[0];
assertScopeInformation(testScope3);
is(testScope3.scope.asyncC, "3", "Async frame value is correct");
});
function cyclicReference() {
const a = {};
const b = { a };
a.b = b;
return dumpScope({ saveAsFile: false });
}
add_task(async function testCyclicReference() {
const scopes = await cyclicReference();
is(scopes.length, 2, "dumpScope returned 2 frames");
const testScope = scopes[0];
assertScopeInformation(testScope);
is(typeof testScope.scope.a, "object", "Cyclic object type is correct");
// Note that the actual way cyclic references are handled could change in the
// future. If we decide to start handling them as references, this test should
// simply be updated!
is(typeof testScope.scope.a.b, "object", "Cyclic object type is correct");
is(typeof testScope.scope.a.b.a, "object", "Cyclic object type is correct");
is(typeof testScope.scope.a.b.a.b, "object", "Cyclic object type is correct");
is(
testScope.scope.a.b.a.b.a,
"Object (max depth)",
"Cyclic object value is correct"
);
});
function maxDepth() {
const obj = {};
let o = obj;
for (let i = 0; i < 100; i++) {
o = o[`a${i}`] = {};
}
return dumpScope({ saveAsFile: false });
}
add_task(async function testMaxDepth() {
const scopes = await maxDepth();
is(scopes.length, 2, "dumpScope returned 2 frames");
const testScope = scopes[0];
assertScopeInformation(testScope);
is(typeof testScope.scope.obj, "object", "Max depth object type is correct");
is(
typeof testScope.scope.obj.a0,
"object",
"Max depth object type is correct"
);
is(
typeof testScope.scope.obj.a0.a1,
"object",
"Max depth object type is correct"
);
is(
typeof testScope.scope.obj.a0.a1.a2,
"object",
"Max depth object type is correct"
);
is(
typeof testScope.scope.obj.a0.a1.a2.a3,
"string",
"Max depth object type is correct"
);
is(
testScope.scope.obj.a0.a1.a2.a3,
"Object (max depth)",
"Max depth object value is correct"
);
});
/**
* Basic test helper to assert the shape of the frame object
*/
function assertScopeInformation(scopeInfo) {
is(
scopeInfo.details.frameScriptUrl,
);
is(typeof scopeInfo.details.columnNumber, "number");
is(typeof scopeInfo.details.lineNumber, "number");
is(typeof scopeInfo.scope, "object");
}