diff options
Diffstat (limited to 'devtools/shared/test-helpers/test-stepper.js')
-rw-r--r-- | devtools/shared/test-helpers/test-stepper.js | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/devtools/shared/test-helpers/test-stepper.js b/devtools/shared/test-helpers/test-stepper.js new file mode 100644 index 0000000000..314a687dbf --- /dev/null +++ b/devtools/shared/test-helpers/test-stepper.js @@ -0,0 +1,97 @@ +/* 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/. */ + +"use strict"; + +const { + startTracing, + addTracingListener, + stopTracing, + removeTracingListener, +} = require("resource://devtools/server/tracer/tracer.jsm"); + +let testFileContent; + +function traceFrame({ frame }) { + const { script } = frame; + const { lineNumber, columnNumber } = script.getOffsetMetadata(frame.offset); + + const { url } = script.source; + const filename = url.substr(url.lastIndexOf("/") + 1); + const line = testFileContent[lineNumber - 1]; + // Grey out the beginning of the line, before frame's column, + // and display an arrow before displaying the rest of the line. + const code = + "\x1b[2m" + + line.substr(0, columnNumber - 1) + + "\x1b[0m" + + "\u21A6 " + + line.substr(columnNumber - 1); + + const position = (lineNumber + ":" + columnNumber).padEnd(7); + logStep(`${filename} @ ${position} :: ${code}`); + + // Disable builtin tracer logging + return false; +} + +function logStep(message) { + dump(` \x1b[2m[STEP]\x1b[0m ${message}\n`); +} + +const tracingListener = { + onTracingFrame: traceFrame, + onTracingFrameStep: traceFrame, +}; + +exports.start = function (testGlobal, testUrl, pause) { + const tracerOptions = { + global: testGlobal, + // Ensure tracing each execution within functions (and not only function calls) + traceSteps: true, + // Only trace the running test and nothing else + filterFrameSourceUrl: testUrl, + }; + testFileContent = readURI(testUrl).split("\n"); + // Only pause on each step if the passed value is a number, + // otherwise we are only going to print each executed line in the test script. + if (!isNaN(pause)) { + // Delay each step by an amount of milliseconds + tracerOptions.pauseOnStep = Number(pause); + logStep(`Tracing all test script steps with ${pause}ms pause`); + logStep( + `/!\\ Be conscious about each pause releasing the event loop and breaking run-to-completion.` + ); + } else { + logStep(`Tracing all test script steps`); + } + logStep( + `'\u21A6 ' symbol highlights what precise instruction is being called` + ); + startTracing(tracerOptions); + addTracingListener(tracingListener); +}; + +exports.stop = function () { + stopTracing(); + removeTracingListener(tracingListener); +}; + +function readURI(uri) { + const { NetUtil } = ChromeUtils.importESModule( + "resource://gre/modules/NetUtil.sys.mjs", + { global: "contextual" } + ); + const stream = NetUtil.newChannel({ + uri: NetUtil.newURI(uri, "UTF-8"), + loadUsingSystemPrincipal: true, + }).open(); + const count = stream.available(); + const data = NetUtil.readInputStreamToString(stream, count, { + charset: "UTF-8", + }); + + stream.close(); + return data; +} |