Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* 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/. */
/**
* Test that the source table in the profile includes all necessary information.
*/
add_task(async function test_source_table_schema() {
Assert.ok(
!Services.profiler.IsActive(),
"The profiler is not currently active"
);
const url = BASE_URL_HTTPS + "simple.html";
await BrowserTestUtils.withNewTab(url, async contentBrowser => {
await ProfilerTestUtils.startProfiler({ features: ["js", "jssources"] });
const contentPid = await SpecialPowers.spawn(
contentBrowser,
[],
() => Services.appinfo.processID
);
// Execute some inline JavaScript to create sources.
await SpecialPowers.spawn(contentBrowser, [], () => {
content.window.eval(`
function testFunction() {
return 42;
}
testFunction();
`);
});
const { contentProcess } = await stopProfilerNowAndGetThreads(contentPid);
Assert.ok(
!!contentProcess,
"Full profile should include the child process"
);
// Check that the profile has a source table.
Assert.ok(!!contentProcess.sources, "Profile should have a source table");
// Check the schema.
const { schema } = contentProcess.sources;
Assert.ok(!!schema, "Source table should have a schema");
Assert.strictEqual(typeof schema, "object", "Schema should be an object");
// Verify the schema includes all necessary keys.
Assert.ok(
Object.keys(schema).includes("id"),
"Schema should include 'id' key"
);
Assert.ok(
Object.keys(schema).includes("filename"),
"Schema should include 'filename' key"
);
Assert.ok(
Object.keys(schema).includes("startLine"),
"Schema should include 'startLine' key"
);
Assert.ok(
Object.keys(schema).includes("startColumn"),
"Schema should include 'startColumn' key"
);
info(`Source table schema keys: [${Object.keys(schema).join(", ")}]`);
// Check that we have some source data.
const { data } = contentProcess.sources;
Assert.ok(!!data, "Source table should have data");
Assert.ok(Array.isArray(data), "Data should be an array");
Assert.greater(data.length, 0, "Should have at least one source");
// Find the expected field indices from the schema.
const idIndex = schema.id;
const filenameIndex = schema.filename;
const startLineIndex = schema.startLine;
const startColumnIndex = schema.startColumn;
// Verify each source entry has the correct structure.
for (const source of data) {
Assert.ok(Array.isArray(source), "Each source should be an array");
Assert.greaterOrEqual(
Object.keys(schema).length,
source.length,
"Source entry should be either the same length or lower due to omitted entries"
);
// Check id (should be a string).
const id = source[idIndex];
Assert.equal(typeof id, "string", "Id should be a string");
// Check filename (can be null or a string).
const filename = source[filenameIndex];
Assert.ok(
filename === null || typeof filename === "string",
"Filename should be null or a string"
);
// Check startLine (should be a number).
const startLine = source[startLineIndex];
Assert.equal(typeof startLine, "number", "startLine should be a number");
Assert.greaterOrEqual(startLine, 1, "startLine should be >= 1 (1-based)");
// Check startColumn (should be a number).
const startColumn = source[startColumnIndex];
Assert.equal(
typeof startColumn,
"number",
"startColumn should be a number"
);
Assert.greaterOrEqual(
startColumn,
1,
"startColumn should be >= 1 (1-based)"
);
info(
`Source: id=${id}, filename=${filename}, ` +
`startLine=${startLine}, startColumn=${startColumn}`
);
}
});
});
/**
* Test that inline scripts have correct startLine and startColumn values.
*/
add_task(async function test_inline_script_start_positions() {
Assert.ok(
!Services.profiler.IsActive(),
"The profiler is not currently active"
);
await ProfilerTestUtils.startProfiler({
features: ["stackwalk", "js", "jssources"],
});
const url = BASE_URL_HTTPS + "inline_script_test.html";
await BrowserTestUtils.withNewTab(url, async contentBrowser => {
const contentPid = await SpecialPowers.spawn(
contentBrowser,
[],
() => Services.appinfo.processID
);
// Wait a bit for scripts to execute.
await SpecialPowers.spawn(contentBrowser, [], () => {
return new Promise(resolve => {
content.window.setTimeout(resolve, 100);
});
});
const { contentProcess } = await stopProfilerNowAndGetThreads(contentPid);
Assert.ok(
!!contentProcess,
"Full profile should include the child process"
);
// Check source table.
Assert.ok(!!contentProcess.sources, "Profile should have a source table");
const { schema, data } = contentProcess.sources;
const startLineIndex = schema.startLine;
const startColumnIndex = schema.startColumn;
const filenameIndex = schema.filename;
// Look for inline script sources (they'll have inline_script_test.html as filename).
const inlineSources = data.filter(source => {
const filename = source[filenameIndex];
return filename && filename.includes("inline_script_test.html");
});
Assert.greater(inlineSources.length, 0, "Should find inline sources");
info(`Found ${inlineSources.length} inline script source(s)`);
for (const source of inlineSources) {
const startLine = source[startLineIndex];
const startColumn = source[startColumnIndex];
const filename = source[filenameIndex];
info(
`Inline source: filename=${filename}, ` +
`startLine=${startLine}, startColumn=${startColumn}`
);
// For inline scripts, we expect specific line numbers.
// Note: These are 1-based indices, so we expect them to be greater than 1.
Assert.greater(startLine, 1, `startLine should be valid: ${startLine}`);
Assert.greater(
startColumn,
1,
`startColumn should be valid: ${startColumn}`
);
}
});
});