summaryrefslogtreecommitdiffstats
path: root/devtools/shared/test-helpers/test-stepper.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/shared/test-helpers/test-stepper.js')
-rw-r--r--devtools/shared/test-helpers/test-stepper.js97
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;
+}